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

[01/43] git commit: Remove plugin_loader. prepare now calls plugman --prepare

Updated Branches:
  refs/heads/master 72cca5ec4 -> 51901bd9f


Remove plugin_loader. prepare now calls plugman --prepare


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

Branch: refs/heads/master
Commit: bdd9210bacd54874c39d5e46b11825084ff4aadd
Parents: 50e8e4e
Author: Braden Shepherdson <br...@gmail.com>
Authored: Mon Mar 25 14:40:50 2013 -0400
Committer: Braden Shepherdson <br...@gmail.com>
Committed: Mon Mar 25 14:40:50 2013 -0400

----------------------------------------------------------------------
 src/plugin_loader.js |  193 ---------------------------------------------
 src/prepare.js       |   10 ++-
 2 files changed, 8 insertions(+), 195 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bdd9210b/src/plugin_loader.js
----------------------------------------------------------------------
diff --git a/src/plugin_loader.js b/src/plugin_loader.js
deleted file mode 100644
index 1733e97..0000000
--- a/src/plugin_loader.js
+++ /dev/null
@@ -1,193 +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 path            = require('path'),
-    fs              = require('fs'),
-    shell           = require('shelljs'),
-    ls              = fs.readdirSync,
-    cordova_util    = require('./util'),
-    util            = require('util'),
-    android_parser  = require('./metadata/android_parser'),
-    blackberry_parser= require('./metadata/blackberry_parser'),
-    ios_parser      = require('./metadata/ios_parser'),
-    exec            = require('child_process').exec,
-    et              = require('elementtree');
-
-
-// Called during cordova prepare.
-// Sets up each plugin's Javascript code to be loaded properly.
-module.exports = function plugin_loader(platform) {
-    // Process:
-    // - List all plugins in plugins/.
-    // - Load and parse their plugin.xml files.
-    // - Skip those without support for this platform.
-    // - Build a list of all their js-modules, and platform-specific js-modules.
-    // - For each js-module (general first, then platform):
-    //   - Generate JS code to load it.
-    //   - For each <clobbers>, <merges> or <runs>, generate JS code to perform it.
-    //   - Copy the file, having slapped the cordova.define onto it on the way.
-    // - Append all of this code to the platform's cordova.js
-
-    var projectRoot = cordova_util.isCordova(process.cwd());
-    var plugins_dir = path.join(projectRoot, 'plugins');
-    var plugins = ls(plugins_dir);
-
-
-    // Placed at the top of cordova.js to delay onDeviceReady until all the plugins
-    // are actually loaded. This is a temporary hack that can be removed once this
-    // prototype is rolled into the main code.
-    var topJS = 'window.__onPluginsLoadedHack = true;\n';
-
-    // The main injected JS, used to inject <script> tags.
-    var js = '';
-
-    // The last part of the injected JS, which runs after all plugins are loaded and
-    // registers the clobbers, merges and runs.
-    var lateJS = '';
-
-    // Add the callback function.
-    js += 'var mapper = cordova.require("cordova/modulemapper");\n';
-    js += 'var scriptCounter = 0;\n';
-    js += 'var scriptCallback = function() {\n';
-    js += 'scriptCounter--;\n';
-    js += 'if (scriptCounter == 0) { scriptsLoaded(); } };\n';
-
-    // <script> tag injection function
-    js += 'function injectScript(path) {\n';
-        js += 'scriptCounter++;\n';
-        js += 'var script = document.createElement("script");\n';
-        js += 'script.onload = scriptCallback;\n';
-        js += 'script.src = path;\n';
-        js += 'document.querySelector("head").appendChild(script);\n';
-    js += '}\n\n';
-
-
-    // Acquire the platform's parser.
-    var parser;
-    switch(platform) {
-        case 'android':
-            parser = new android_parser(path.join(projectRoot, 'platforms', 'android'));
-            break;
-        case 'ios':
-            parser = new ios_parser(path.join(projectRoot, 'platforms', 'ios'));
-            break;
-        case 'blackberry':
-            parser = new blackberry_parser(path.join(projectRoot, 'platforms', 'blackberry'));
-            break;
-    }
-
-    plugins && plugins.forEach(function(plugin) {
-        var pluginDir = path.join(projectRoot, 'plugins', plugin);
-        var xml = new et.ElementTree(et.XML(fs.readFileSync(path.join(pluginDir, 'plugin.xml'), 'utf-8')));
-
-        var plugin_id = xml.getroot().attrib.id;
-
-        // Copy all the <asset>s into the platform's www/
-        var assets = xml.findall('./asset');
-        assets && assets.forEach(function(asset) {
-            var target = asset.attrib.target;
-            var lastSlash = target.lastIndexOf('/');
-            var dirname  = lastSlash < 0 ? ''     : target.substring(0, lastSlash);
-            var basename = lastSlash < 0 ? target : target.substring(lastSlash + 1);
-
-            var targetDir = path.join(parser.www_dir(), dirname);
-            shell.mkdir('-p', targetDir);
-
-            var srcFile = path.join(pluginDir, asset.attrib.src);
-            var targetFile = path.join(targetDir, basename);
-
-            var cpOptions = fs.statSync(srcFile).isDirectory() ? '-Rf' : '-f';
-            shell.cp(cpOptions, [srcFile], targetFile);
-        });
-
-        // And then add the plugins dir to the platform's www.
-        var platformPluginsDir = path.join(parser.www_dir(), 'plugins');
-        shell.mkdir('-p', platformPluginsDir);
-
-        var generalModules = xml.findall('./js-module');
-        var platformTag = xml.find(util.format('./platform[@name="%s"]', platform));
-        if (!platformTag) {
-            return; // Skip plugins that don't support this platform.
-        }
-
-        var platformModules = platformTag.findall('./js-module');
-        generalModules = generalModules || [];
-        var allModules = generalModules.concat(platformModules);
-
-
-        allModules.forEach(function(module) {
-            // Copy the plugin's files into the www directory.
-            var dirname = module.attrib.src;
-            var lastSlash = dirname.lastIndexOf('/');
-            if (lastSlash >= 0) {
-                dirname = dirname.substring(0, lastSlash);
-            } else {
-                dirname = ''; // Just the file, no subdir.
-            }
-
-            var dir = path.join(platformPluginsDir, plugin_id, dirname);
-            shell.mkdir('-p', dir);
-
-            // Read in the file, prepend the cordova.define, and write it back out.
-            var moduleName = plugin_id + '.';
-            if (module.attrib.name) {
-                moduleName += module.attrib.name;
-            } else {
-                var result = module.attrib.src.match(/([^\/]+)\.js/);
-                moduleName += result[1];
-            }
-
-            var scriptContent = fs.readFileSync(path.join(pluginDir, module.attrib.src), 'utf-8');
-            scriptContent = 'cordova.define("' + moduleName + '", function(require, exports, module) {' + scriptContent + '});\n';
-            fs.writeFileSync(path.join(platformPluginsDir, plugin_id, module.attrib.src), scriptContent, 'utf-8');
-
-            // Prepare the injected Javascript code.
-            var jsFile = path.join('plugins', plugin_id, module.attrib.src);
-            js += 'injectScript("' + jsFile + '");\n';
-
-            // Loop over the children, injecting clobber, merge and run code for each.
-            module.getchildren().forEach(function(child) {
-                if (child.tag.toLowerCase() == 'clobbers') {
-                    lateJS += 'mapper.clobbers("' + moduleName + '", "' + child.attrib.target + '");\n';
-                } else if (child.tag.toLowerCase() == 'merges') {
-                    lateJS += 'mapper.merges("' + moduleName + '", "' + child.attrib.target + '");\n';
-                } else if (child.tag.toLowerCase() == 'runs') {
-                    lateJS += 'cordova.require("' + moduleName + '");\n';
-                }
-            });
-            lateJS += '\n\n\n';
-        });
-    });
-
-    // Last step in lateJS that runs after the <script> tags have all loaded and
-    // all modules are properly clobbered: fire onPluginsReady event.
-    lateJS += 'cordova.require("cordova/channel").onPluginsReady.fire();\n';
-
-    // Wrap lateJS into scriptsLoaded(), which will be called after the last <script>
-    // has finished loading.
-    lateJS = 'function scriptsLoaded() {\n' + lateJS + '\n}\n';
-
-    // Now write the generated JS to the platform's cordova.js
-    var cordovaJSPath = path.join(parser.www_dir(), 'cordova.js');
-    var cordovaJS = fs.readFileSync(cordovaJSPath, 'utf-8');
-    cordovaJS = topJS + cordovaJS + '(function() { ' + js + lateJS + '})();';
-    fs.writeFileSync(cordovaJSPath, cordovaJS, 'utf-8');
-};
-
-

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bdd9210b/src/prepare.js
----------------------------------------------------------------------
diff --git a/src/prepare.js b/src/prepare.js
index a5d3ee7..0d47acd 100644
--- a/src/prepare.js
+++ b/src/prepare.js
@@ -29,7 +29,6 @@ var cordova_util      = require('./util'),
     hooker            = require('./hooker'),
     n                 = require('ncallbacks'),
     prompt            = require('prompt'),
-    plugin_loader = require('./plugin_loader'),
     util              = require('util');
 
 var parsers = {
@@ -70,12 +69,19 @@ module.exports = function prepare(platforms, callback) {
         if (callback) callback();
     });
 
+    var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'plugman.js');
+
     // Iterate over each added platform
     platforms.forEach(function(platform) {
         var platformPath = path.join(projectRoot, 'platforms', platform);
         var parser = new parsers[platform](platformPath);
         parser.update_project(cfg, function() {
-            plugin_loader(platform);
+            // Call plugman --prepare for each platform.
+            var cmd = util.format('%s --prepare --platform "%s" --project "%s" --www "%s" --plugins_dir "%s"', cli, platform, platformPath, parser.www_dir(), path.join(projectRoot, 'plugins'));
+            console.log(cmd);
+            var plugman_call = shell.exec(cmd, {silent:true});
+            if (plugman_call.code > 0) throw new Error('An error occurred during plugman --prepare for ' + platform + ': ' + plugman_call.output);
+
             end();
         });
     });


[16/43] git commit: Fix `cordova prepare` now that plugin assets are copied on (un)install

Posted by an...@apache.org.
Fix `cordova prepare` now that plugin assets are copied on (un)install

This change introduces a new platform/foo/.staging/www directory, into
which plugin assets are installed by plugman. cordova prepare copies
these on top of the platform-specific www directory.

The platform-specific www directories are still deleted and recreated on
every prepare.

Uninstallation is working, plugman tests are passing, CLI tests are
broken but this change isn't the problem.


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

Branch: refs/heads/master
Commit: 2a5407e8bf840c9f004eab7a147fd69824409167
Parents: 655776c
Author: Braden Shepherdson <br...@gmail.com>
Authored: Wed May 8 15:26:31 2013 -0400
Committer: Braden Shepherdson <br...@gmail.com>
Committed: Wed May 8 17:17:41 2013 -0400

----------------------------------------------------------------------
 src/metadata/android_parser.js    |   14 ++++++++++++++
 src/metadata/blackberry_parser.js |   14 ++++++++++++++
 src/metadata/ios_parser.js        |   14 ++++++++++++++
 src/platform.js                   |   10 +++++-----
 src/plugin.js                     |   19 +++++++++++++------
 src/prepare.js                    |    9 +--------
 6 files changed, 61 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/2a5407e8/src/metadata/android_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/android_parser.js b/src/metadata/android_parser.js
index 70e952a..be3015c 100644
--- a/src/metadata/android_parser.js
+++ b/src/metadata/android_parser.js
@@ -126,6 +126,10 @@ module.exports.prototype = {
         return path.join(this.path, 'assets', 'www');
     },
 
+    staging_dir: function() {
+        return path.join(this.path, '.staging', 'www');
+    },
+
     update_www:function() {
         var projectRoot = util.isCordova(this.path);
         var www = util.projectWww(projectRoot);
@@ -151,11 +155,21 @@ module.exports.prototype = {
         }
     },
 
+    // update the overrides folder into the www folder
+    update_staging:function() {
+        var projectRoot = util.isCordova(this.path);
+        if (fs.existsSync(this.staging_dir())) {
+            var staging = path.join(this.staging_dir(), '*');
+            shell.cp('-rf', staging, this.www_dir());
+        }
+    },
+
     update_project:function(cfg, callback) {
         var platformWww = path.join(this.path, 'assets');
         this.update_from_config(cfg);
         this.update_www();
         this.update_overrides();
+        this.update_staging();
         // delete any .svn folders copied over
         util.deleteSvnFolders(platformWww);
         if (callback) callback();

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/2a5407e8/src/metadata/blackberry_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/blackberry_parser.js b/src/metadata/blackberry_parser.js
index 5bd6d84..16fcbad 100644
--- a/src/metadata/blackberry_parser.js
+++ b/src/metadata/blackberry_parser.js
@@ -64,6 +64,7 @@ module.exports.prototype = {
         self.update_from_config(cfg);
         self.update_www();
         self.update_overrides();
+        self.update_staging();
         util.deleteSvnFolders(this.www_dir());
 
         // Do we have BB config?
@@ -89,6 +90,10 @@ module.exports.prototype = {
         return path.join(this.path, 'www');
     },
 
+    staging_dir: function() {
+        return path.join(this.path, '.staging', 'www');
+    },
+
     update_www:function() {
         var projectRoot = util.isCordova(this.path);
         var www = util.projectWww(projectRoot);
@@ -129,6 +134,15 @@ module.exports.prototype = {
         }
     },
 
+    // update the overrides folder into the www folder
+    update_staging:function() {
+        var projectRoot = util.isCordova(this.path);
+        if (fs.existsSync(this.staging_dir())) {
+            var staging = path.join(this.staging_dir(), '*');
+            shell.cp('-rf', staging, this.www_dir());
+        }
+    },
+
     write_project_properties:function() {
         // TODO: eventually support all blackberry sub-platforms
         var projectRoot = util.isCordova(this.path);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/2a5407e8/src/metadata/ios_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/ios_parser.js b/src/metadata/ios_parser.js
index e3b19fd..5e83ed3 100644
--- a/src/metadata/ios_parser.js
+++ b/src/metadata/ios_parser.js
@@ -137,6 +137,10 @@ module.exports.prototype = {
         return path.join(this.path, 'www');
     },
 
+    staging_dir: function() {
+        return path.join(this.path, '.staging', 'www');
+    },
+
     update_www:function() {
         var projectRoot = util.isCordova(this.path);
         var www = util.projectWww(projectRoot);
@@ -163,11 +167,21 @@ module.exports.prototype = {
         }
     },
 
+    // update the overrides folder into the www folder
+    update_staging:function() {
+        var projectRoot = util.isCordova(this.path);
+        if (fs.existsSync(this.staging_dir())) {
+            var staging = path.join(this.staging_dir(), '*');
+            shell.cp('-rf', staging, this.www_dir());
+        }
+    },
+
     update_project:function(cfg, callback) {
         var self = this;
         this.update_from_config(cfg, function() {
             self.update_www();
             self.update_overrides();
+            self.update_staging();
             util.deleteSvnFolders(self.www_dir());
             if (callback) callback();
         });

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/2a5407e8/src/platform.js
----------------------------------------------------------------------
diff --git a/src/platform.js b/src/platform.js
index 587e687..1e51c6c 100644
--- a/src/platform.js
+++ b/src/platform.js
@@ -26,6 +26,7 @@ var config_parser     = require('./config_parser'),
     android_parser    = require('./metadata/android_parser'),
     ios_parser        = require('./metadata/ios_parser'),
     blackberry_parser = require('./metadata/blackberry_parser'),
+    plugman           = require('plugman'),
     shell             = require('shelljs');
 
 var parsers = {
@@ -107,12 +108,11 @@ module.exports = function platform(command, targets, callback) {
                                 var pluginsDir = path.join(projectRoot, 'plugins');
                                 var plugins = fs.readdirSync(pluginsDir);
                                 plugins && plugins.forEach(function(plugin) {
-                                    var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'main.js');
-                                    var cmd = util.format('"%s" --platform "%s" --project "%s" --plugin "%s" --plugins_dir "%s"', cli, target, output, path.basename(plugin), pluginsDir);
-                                    var result = shell.exec(cmd, { silent: true });
-                                    if (result.code > 0) {
-                                        throw new Error('An error occurred while installing the ' + path.basename(plugin) + ' plugin: ' + result.output);
+                                    if (!fs.statSync(path.join(projectRoot, 'plugins', plugin)).isDirectory()) {
+                                        return;
                                     }
+
+                                    plugman.install(target, output, path.basename(plugin), pluginsDir, {}, parser.staging_dir());
                                 });
                                 end();
                             });

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/2a5407e8/src/plugin.js
----------------------------------------------------------------------
diff --git a/src/plugin.js b/src/plugin.js
index 9f3138d..355157d 100644
--- a/src/plugin.js
+++ b/src/plugin.js
@@ -24,12 +24,16 @@ var cordova_util  = require('./util'),
     shell         = require('shelljs'),
     config_parser = require('./config_parser'),
     hooker        = require('./hooker'),
-    core_platforms= require('../platforms'),
-    platform      = require('./platform'),
     plugin_parser = require('./plugin_parser'),
     ls            = fs.readdirSync,
     plugman       = require('plugman');
 
+var parsers = {
+    "android": require('./metadata/android_parser'),
+    "ios": require('./metadata/ios_parser'),
+    "blackberry": require('./metadata/blackberry_parser')
+};
+
 module.exports = function plugin(command, targets, callback) {
     var projectRoot = cordova_util.isCordova(process.cwd());
 
@@ -84,10 +88,11 @@ module.exports = function plugin(command, targets, callback) {
                 plugman.fetch(target, pluginsDir, false);
                 
                 // Iterate over all platforms in the project and install the plugin.
-                // TODO add cli_variables if it's important (last argument) ?
                 platforms.forEach(function(platform) {
-                    plugman.install(platform, path.join(projectRoot, 'platforms', platform), 
-                                    names[index], pluginsDir, {});
+                    var platformRoot = path.join(projectRoot, 'platforms', platform);
+                    var parser = new parsers[platform](platformRoot);
+                    plugman.install(platform, platformRoot,
+                                    names[index], pluginsDir, {}, parser.staging_dir());
                 });
 
                 hooks.fire('after_plugin_add');
@@ -118,7 +123,9 @@ module.exports = function plugin(command, targets, callback) {
                     // If this is a web-only plugin with no platform tags, this step
                     // is not needed and we just --remove the plugin below.
                     intersection.forEach(function(platform) {
-                        plugman.uninstall(platform, path.join(projectRoot, 'platforms', platform), targetName, path.join(projectRoot, 'plugins'));
+                        var platformRoot = path.join(projectRoot, 'platforms', platform);
+                        var parser = new parsers[platform](platformRoot);
+                        plugman.uninstall(platform, platformRoot, targetName, path.join(projectRoot, 'plugins'), {}, parser.staging_dir());
                     });
 
                     // Finally remove the plugin dir from plugins/

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/2a5407e8/src/prepare.js
----------------------------------------------------------------------
diff --git a/src/prepare.js b/src/prepare.js
index 0b6d060..06a6a18 100644
--- a/src/prepare.js
+++ b/src/prepare.js
@@ -75,13 +75,6 @@ module.exports = function prepare(platforms, callback) {
     platforms.forEach(function(platform) {
         var platformPath = path.join(projectRoot, 'platforms', platform);
         var parser = new parsers[platform](platformPath);
-        parser.update_project(cfg, function() {
-            // Call plugman --prepare for each platform.
-            var cmd = util.format('%s --prepare --platform "%s" --project "%s" --www "%s" --plugins_dir "%s"', cli, platform, platformPath, parser.www_dir(), path.join(projectRoot, 'plugins'));
-            var plugman_call = shell.exec(cmd, {silent:true});
-            if (plugman_call.code > 0) throw new Error('An error occurred during plugman --prepare for ' + platform + ': ' + plugman_call.output);
-
-            end();
-        });
+        parser.update_project(cfg, end);
     });
 };


[10/43] Move www/ and merges/ into app/.

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/spec/lib/jasmine-1.2.0/jasmine-html.js
----------------------------------------------------------------------
diff --git a/templates/app/www/spec/lib/jasmine-1.2.0/jasmine-html.js b/templates/app/www/spec/lib/jasmine-1.2.0/jasmine-html.js
new file mode 100644
index 0000000..a0b0639
--- /dev/null
+++ b/templates/app/www/spec/lib/jasmine-1.2.0/jasmine-html.js
@@ -0,0 +1,616 @@
+jasmine.HtmlReporterHelpers = {};
+
+jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
+  var el = document.createElement(type);
+
+  for (var i = 2; i < arguments.length; i++) {
+    var child = arguments[i];
+
+    if (typeof child === 'string') {
+      el.appendChild(document.createTextNode(child));
+    } else {
+      if (child) {
+        el.appendChild(child);
+      }
+    }
+  }
+
+  for (var attr in attrs) {
+    if (attr == "className") {
+      el[attr] = attrs[attr];
+    } else {
+      el.setAttribute(attr, attrs[attr]);
+    }
+  }
+
+  return el;
+};
+
+jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
+  var results = child.results();
+  var status = results.passed() ? 'passed' : 'failed';
+  if (results.skipped) {
+    status = 'skipped';
+  }
+
+  return status;
+};
+
+jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
+  var parentDiv = this.dom.summary;
+  var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
+  var parent = child[parentSuite];
+
+  if (parent) {
+    if (typeof this.views.suites[parent.id] == 'undefined') {
+      this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
+    }
+    parentDiv = this.views.suites[parent.id].element;
+  }
+
+  parentDiv.appendChild(childElement);
+};
+
+
+jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
+  for(var fn in jasmine.HtmlReporterHelpers) {
+    ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
+  }
+};
+
+jasmine.HtmlReporter = function(_doc) {
+  var self = this;
+  var doc = _doc || window.document;
+
+  var reporterView;
+
+  var dom = {};
+
+  // Jasmine Reporter Public Interface
+  self.logRunningSpecs = false;
+
+  self.reportRunnerStarting = function(runner) {
+    var specs = runner.specs() || [];
+
+    if (specs.length == 0) {
+      return;
+    }
+
+    createReporterDom(runner.env.versionString());
+    doc.body.appendChild(dom.reporter);
+
+    reporterView = new jasmine.HtmlReporter.ReporterView(dom);
+    reporterView.addSpecs(specs, self.specFilter);
+  };
+
+  self.reportRunnerResults = function(runner) {
+    reporterView && reporterView.complete();
+  };
+
+  self.reportSuiteResults = function(suite) {
+    reporterView.suiteComplete(suite);
+  };
+
+  self.reportSpecStarting = function(spec) {
+    if (self.logRunningSpecs) {
+      self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+    }
+  };
+
+  self.reportSpecResults = function(spec) {
+    reporterView.specComplete(spec);
+  };
+
+  self.log = function() {
+    var console = jasmine.getGlobal().console;
+    if (console && console.log) {
+      if (console.log.apply) {
+        console.log.apply(console, arguments);
+      } else {
+        console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+      }
+    }
+  };
+
+  self.specFilter = function(spec) {
+    if (!focusedSpecName()) {
+      return true;
+    }
+
+    return spec.getFullName().indexOf(focusedSpecName()) === 0;
+  };
+
+  return self;
+
+  function focusedSpecName() {
+    var specName;
+
+    (function memoizeFocusedSpec() {
+      if (specName) {
+        return;
+      }
+
+      var paramMap = [];
+      var params = doc.location.search.substring(1).split('&');
+
+      for (var i = 0; i < params.length; i++) {
+        var p = params[i].split('=');
+        paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+      }
+
+      specName = paramMap.spec;
+    })();
+
+    return specName;
+  }
+
+  function createReporterDom(version) {
+    dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
+      dom.banner = self.createDom('div', { className: 'banner' },
+        self.createDom('span', { className: 'title' }, "Jasmine "),
+        self.createDom('span', { className: 'version' }, version)),
+
+      dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
+      dom.alert = self.createDom('div', {className: 'alert'}),
+      dom.results = self.createDom('div', {className: 'results'},
+        dom.summary = self.createDom('div', { className: 'summary' }),
+        dom.details = self.createDom('div', { id: 'details' }))
+    );
+  }
+};
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);jasmine.HtmlReporter.ReporterView = function(dom) {
+  this.startedAt = new Date();
+  this.runningSpecCount = 0;
+  this.completeSpecCount = 0;
+  this.passedCount = 0;
+  this.failedCount = 0;
+  this.skippedCount = 0;
+
+  this.createResultsMenu = function() {
+    this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
+      this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
+      ' | ',
+      this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
+
+    this.summaryMenuItem.onclick = function() {
+      dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
+    };
+
+    this.detailsMenuItem.onclick = function() {
+      showDetails();
+    };
+  };
+
+  this.addSpecs = function(specs, specFilter) {
+    this.totalSpecCount = specs.length;
+
+    this.views = {
+      specs: {},
+      suites: {}
+    };
+
+    for (var i = 0; i < specs.length; i++) {
+      var spec = specs[i];
+      this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
+      if (specFilter(spec)) {
+        this.runningSpecCount++;
+      }
+    }
+  };
+
+  this.specComplete = function(spec) {
+    this.completeSpecCount++;
+
+    if (isUndefined(this.views.specs[spec.id])) {
+      this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
+    }
+
+    var specView = this.views.specs[spec.id];
+
+    switch (specView.status()) {
+      case 'passed':
+        this.passedCount++;
+        break;
+
+      case 'failed':
+        this.failedCount++;
+        break;
+
+      case 'skipped':
+        this.skippedCount++;
+        break;
+    }
+
+    specView.refresh();
+    this.refresh();
+  };
+
+  this.suiteComplete = function(suite) {
+    var suiteView = this.views.suites[suite.id];
+    if (isUndefined(suiteView)) {
+      return;
+    }
+    suiteView.refresh();
+  };
+
+  this.refresh = function() {
+
+    if (isUndefined(this.resultsMenu)) {
+      this.createResultsMenu();
+    }
+
+    // currently running UI
+    if (isUndefined(this.runningAlert)) {
+      this.runningAlert = this.createDom('a', {href: "?", className: "runningAlert bar"});
+      dom.alert.appendChild(this.runningAlert);
+    }
+    this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
+
+    // skipped specs UI
+    if (isUndefined(this.skippedAlert)) {
+      this.skippedAlert = this.createDom('a', {href: "?", className: "skippedAlert bar"});
+    }
+
+    this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+    if (this.skippedCount === 1 && isDefined(dom.alert)) {
+      dom.alert.appendChild(this.skippedAlert);
+    }
+
+    // passing specs UI
+    if (isUndefined(this.passedAlert)) {
+      this.passedAlert = this.createDom('span', {href: "?", className: "passingAlert bar"});
+    }
+    this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
+
+    // failing specs UI
+    if (isUndefined(this.failedAlert)) {
+      this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
+    }
+    this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
+
+    if (this.failedCount === 1 && isDefined(dom.alert)) {
+      dom.alert.appendChild(this.failedAlert);
+      dom.alert.appendChild(this.resultsMenu);
+    }
+
+    // summary info
+    this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
+    this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
+  };
+
+  this.complete = function() {
+    dom.alert.removeChild(this.runningAlert);
+
+    this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+    if (this.failedCount === 0) {
+      dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
+    } else {
+      showDetails();
+    }
+
+    dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
+  };
+
+  return this;
+
+  function showDetails() {
+    if (dom.reporter.className.search(/showDetails/) === -1) {
+      dom.reporter.className += " showDetails";
+    }
+  }
+
+  function isUndefined(obj) {
+    return typeof obj === 'undefined';
+  }
+
+  function isDefined(obj) {
+    return !isUndefined(obj);
+  }
+
+  function specPluralizedFor(count) {
+    var str = count + " spec";
+    if (count > 1) {
+      str += "s"
+    }
+    return str;
+  }
+
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
+
+
+jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
+  this.spec = spec;
+  this.dom = dom;
+  this.views = views;
+
+  this.symbol = this.createDom('li', { className: 'pending' });
+  this.dom.symbolSummary.appendChild(this.symbol);
+
+  this.summary = this.createDom('div', { className: 'specSummary' },
+      this.createDom('a', {
+        className: 'description',
+        href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
+        title: this.spec.getFullName()
+      }, this.spec.description)
+  );
+
+  this.detail = this.createDom('div', { className: 'specDetail' },
+      this.createDom('a', {
+        className: 'description',
+        href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
+        title: this.spec.getFullName()
+      }, this.spec.getFullName())
+  );
+};
+
+jasmine.HtmlReporter.SpecView.prototype.status = function() {
+  return this.getSpecStatus(this.spec);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
+  this.symbol.className = this.status();
+
+  switch (this.status()) {
+    case 'skipped':
+      break;
+
+    case 'passed':
+      this.appendSummaryToSuiteDiv();
+      break;
+
+    case 'failed':
+      this.appendSummaryToSuiteDiv();
+      this.appendFailureDetail();
+      break;
+  }
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
+  this.summary.className += ' ' + this.status();
+  this.appendToSummary(this.spec, this.summary);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
+  this.detail.className += ' ' + this.status();
+
+  var resultItems = this.spec.results().getItems();
+  var messagesDiv = this.createDom('div', { className: 'messages' });
+
+  for (var i = 0; i < resultItems.length; i++) {
+    var result = resultItems[i];
+
+    if (result.type == 'log') {
+      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+    } else if (result.type == 'expect' && result.passed && !result.passed()) {
+      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+      if (result.trace.stack) {
+        messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+      }
+    }
+  }
+
+  if (messagesDiv.childNodes.length > 0) {
+    this.detail.appendChild(messagesDiv);
+    this.dom.details.appendChild(this.detail);
+  }
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
+  this.suite = suite;
+  this.dom = dom;
+  this.views = views;
+
+  this.element = this.createDom('div', { className: 'suite' },
+      this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description)
+  );
+
+  this.appendToSummary(this.suite, this.element);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.status = function() {
+  return this.getSpecStatus(this.suite);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
+  this.element.className += " " + this.status();
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
+
+/* @deprecated Use jasmine.HtmlReporter instead
+ */
+jasmine.TrivialReporter = function(doc) {
+  this.document = doc || document;
+  this.suiteDivs = {};
+  this.logRunningSpecs = false;
+};
+
+jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
+  var el = document.createElement(type);
+
+  for (var i = 2; i < arguments.length; i++) {
+    var child = arguments[i];
+
+    if (typeof child === 'string') {
+      el.appendChild(document.createTextNode(child));
+    } else {
+      if (child) { el.appendChild(child); }
+    }
+  }
+
+  for (var attr in attrs) {
+    if (attr == "className") {
+      el[attr] = attrs[attr];
+    } else {
+      el.setAttribute(attr, attrs[attr]);
+    }
+  }
+
+  return el;
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
+  var showPassed, showSkipped;
+
+  this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
+      this.createDom('div', { className: 'banner' },
+        this.createDom('div', { className: 'logo' },
+            this.createDom('span', { className: 'title' }, "Jasmine"),
+            this.createDom('span', { className: 'version' }, runner.env.versionString())),
+        this.createDom('div', { className: 'options' },
+            "Show ",
+            showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
+            this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
+            showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
+            this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
+            )
+          ),
+
+      this.runnerDiv = this.createDom('div', { className: 'runner running' },
+          this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
+          this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
+          this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
+      );
+
+  this.document.body.appendChild(this.outerDiv);
+
+  var suites = runner.suites();
+  for (var i = 0; i < suites.length; i++) {
+    var suite = suites[i];
+    var suiteDiv = this.createDom('div', { className: 'suite' },
+        this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
+        this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
+    this.suiteDivs[suite.id] = suiteDiv;
+    var parentDiv = this.outerDiv;
+    if (suite.parentSuite) {
+      parentDiv = this.suiteDivs[suite.parentSuite.id];
+    }
+    parentDiv.appendChild(suiteDiv);
+  }
+
+  this.startedAt = new Date();
+
+  var self = this;
+  showPassed.onclick = function(evt) {
+    if (showPassed.checked) {
+      self.outerDiv.className += ' show-passed';
+    } else {
+      self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
+    }
+  };
+
+  showSkipped.onclick = function(evt) {
+    if (showSkipped.checked) {
+      self.outerDiv.className += ' show-skipped';
+    } else {
+      self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
+    }
+  };
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
+  var results = runner.results();
+  var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
+  this.runnerDiv.setAttribute("class", className);
+  //do it twice for IE
+  this.runnerDiv.setAttribute("className", className);
+  var specs = runner.specs();
+  var specCount = 0;
+  for (var i = 0; i < specs.length; i++) {
+    if (this.specFilter(specs[i])) {
+      specCount++;
+    }
+  }
+  var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
+  message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
+  this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
+
+  this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
+};
+
+jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
+  var results = suite.results();
+  var status = results.passed() ? 'passed' : 'failed';
+  if (results.totalCount === 0) { // todo: change this to check results.skipped
+    status = 'skipped';
+  }
+  this.suiteDivs[suite.id].className += " " + status;
+};
+
+jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
+  if (this.logRunningSpecs) {
+    this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+  }
+};
+
+jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
+  var results = spec.results();
+  var status = results.passed() ? 'passed' : 'failed';
+  if (results.skipped) {
+    status = 'skipped';
+  }
+  var specDiv = this.createDom('div', { className: 'spec '  + status },
+      this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
+      this.createDom('a', {
+        className: 'description',
+        href: '?spec=' + encodeURIComponent(spec.getFullName()),
+        title: spec.getFullName()
+      }, spec.description));
+
+
+  var resultItems = results.getItems();
+  var messagesDiv = this.createDom('div', { className: 'messages' });
+  for (var i = 0; i < resultItems.length; i++) {
+    var result = resultItems[i];
+
+    if (result.type == 'log') {
+      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+    } else if (result.type == 'expect' && result.passed && !result.passed()) {
+      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+      if (result.trace.stack) {
+        messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+      }
+    }
+  }
+
+  if (messagesDiv.childNodes.length > 0) {
+    specDiv.appendChild(messagesDiv);
+  }
+
+  this.suiteDivs[spec.suite.id].appendChild(specDiv);
+};
+
+jasmine.TrivialReporter.prototype.log = function() {
+  var console = jasmine.getGlobal().console;
+  if (console && console.log) {
+    if (console.log.apply) {
+      console.log.apply(console, arguments);
+    } else {
+      console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+    }
+  }
+};
+
+jasmine.TrivialReporter.prototype.getLocation = function() {
+  return this.document.location;
+};
+
+jasmine.TrivialReporter.prototype.specFilter = function(spec) {
+  var paramMap = {};
+  var params = this.getLocation().search.substring(1).split('&');
+  for (var i = 0; i < params.length; i++) {
+    var p = params[i].split('=');
+    paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+  }
+
+  if (!paramMap.spec) {
+    return true;
+  }
+  return spec.getFullName().indexOf(paramMap.spec) === 0;
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/spec/lib/jasmine-1.2.0/jasmine.css
----------------------------------------------------------------------
diff --git a/templates/app/www/spec/lib/jasmine-1.2.0/jasmine.css b/templates/app/www/spec/lib/jasmine-1.2.0/jasmine.css
new file mode 100644
index 0000000..826e575
--- /dev/null
+++ b/templates/app/www/spec/lib/jasmine-1.2.0/jasmine.css
@@ -0,0 +1,81 @@
+body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
+
+#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
+#HTMLReporter a { text-decoration: none; }
+#HTMLReporter a:hover { text-decoration: underline; }
+#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
+#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
+#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
+#HTMLReporter .version { color: #aaaaaa; }
+#HTMLReporter .banner { margin-top: 14px; }
+#HTMLReporter .duration { color: #aaaaaa; float: right; }
+#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
+#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
+#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
+#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
+#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
+#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
+#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
+#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
+#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
+#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
+#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
+#HTMLReporter .runningAlert { background-color: #666666; }
+#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
+#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
+#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
+#HTMLReporter .passingAlert { background-color: #a6b779; }
+#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
+#HTMLReporter .failingAlert { background-color: #cf867e; }
+#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
+#HTMLReporter .results { margin-top: 14px; }
+#HTMLReporter #details { display: none; }
+#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
+#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
+#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
+#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
+#HTMLReporter.showDetails .summary { display: none; }
+#HTMLReporter.showDetails #details { display: block; }
+#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
+#HTMLReporter .summary { margin-top: 14px; }
+#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
+#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
+#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
+#HTMLReporter .description + .suite { margin-top: 0; }
+#HTMLReporter .suite { margin-top: 14px; }
+#HTMLReporter .suite a { color: #333333; }
+#HTMLReporter #details .specDetail { margin-bottom: 28px; }
+#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
+#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
+#HTMLReporter .resultMessage span.result { display: block; }
+#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
+
+#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
+#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
+#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
+#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
+#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
+#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
+#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
+#TrivialReporter .runner.running { background-color: yellow; }
+#TrivialReporter .options { text-align: right; font-size: .8em; }
+#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
+#TrivialReporter .suite .suite { margin: 5px; }
+#TrivialReporter .suite.passed { background-color: #dfd; }
+#TrivialReporter .suite.failed { background-color: #fdd; }
+#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
+#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
+#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
+#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
+#TrivialReporter .spec.skipped { background-color: #bbb; }
+#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
+#TrivialReporter .passed { background-color: #cfc; display: none; }
+#TrivialReporter .failed { background-color: #fbb; }
+#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
+#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
+#TrivialReporter .resultMessage .mismatch { color: black; }
+#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
+#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
+#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
+#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
+#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }


[34/43] Version 2.7.0-rc.1

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java b/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
index 0d5d496..8e78baa 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
@@ -51,6 +51,7 @@ import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.webkit.WebChromeClient;
 import android.webkit.GeolocationPermissions.Callback;
+import android.webkit.JsPromptResult;
 import android.webkit.WebSettings;
 import android.webkit.WebStorage;
 import android.webkit.WebView;
@@ -92,12 +93,9 @@ public class InAppBrowser extends CordovaPlugin {
      * @return              A PluginResult object with a status and message.
      */
     public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
-        PluginResult.Status status = PluginResult.Status.OK;
-        String result = "";
-        this.callbackContext = callbackContext;
-        
         try {
             if (action.equals("open")) {
+                this.callbackContext = callbackContext;
                 String url = args.getString(0);
                 String target = args.optString(1);
                 if (target == null || target.equals("") || target.equals(NULL)) {
@@ -108,6 +106,7 @@ public class InAppBrowser extends CordovaPlugin {
                 Log.d(LOG_TAG, "target = " + target);
 
                 url = updateUrl(url);
+                String result = "";
 
                 // SELF
                 if (SELF.equals(target)) {
@@ -143,35 +142,52 @@ public class InAppBrowser extends CordovaPlugin {
                     Log.d(LOG_TAG, "in blank");
                     result = this.showWebPage(url, features);
                 }
+
+                PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, result);
+                pluginResult.setKeepCallback(true);
+                this.callbackContext.sendPluginResult(pluginResult);
             }
             else if (action.equals("close")) {
                 closeDialog();
-
-                PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
-                pluginResult.setKeepCallback(false);
-                this.callbackContext.sendPluginResult(pluginResult);
+                this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
             }
             else if (action.equals("injectScriptCode")) {
-                String source = args.getString(0);
-
-                org.json.JSONArray jsonEsc = new org.json.JSONArray();
-                jsonEsc.put(source);
-                String jsonRepr = jsonEsc.toString();
-                String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
-                String scriptEnclosure = "(function(d){var c=d.createElement('script');c.type='text/javascript';c.innerText="
-                                       + jsonSourceString
-                                       + ";d.getElementsByTagName('head')[0].appendChild(c);})(document)";
-                this.inAppWebView.loadUrl("javascript:" + scriptEnclosure);
-
-                PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
-                this.callbackContext.sendPluginResult(pluginResult);
+                String jsWrapper = null;
+                if (args.getBoolean(1)) {
+                    jsWrapper = String.format("prompt(JSON.stringify([eval(%%s)]), 'gap-iab://%s')", callbackContext.getCallbackId());
+                }
+                injectDeferredObject(args.getString(0), jsWrapper);
+            }
+            else if (action.equals("injectScriptFile")) {
+                String jsWrapper;
+                if (args.getBoolean(1)) {
+                    jsWrapper = String.format("(function(d) { var c = d.createElement('script'); c.src = %%s; c.onload = function() { prompt('', 'gap-iab://%s'); }; d.body.appendChild(c); })(document)", callbackContext.getCallbackId());
+                } else {
+                    jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)";
+                }
+                injectDeferredObject(args.getString(0), jsWrapper);
+            }
+            else if (action.equals("injectStyleCode")) {
+                String jsWrapper;
+                if (args.getBoolean(1)) {
+                    jsWrapper = String.format("(function(d) { var c = d.createElement('style'); c.innerHTML = %%s; d.body.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
+                } else {
+                    jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)";
+                }
+                injectDeferredObject(args.getString(0), jsWrapper);
+            }
+            else if (action.equals("injectStyleFile")) {
+                String jsWrapper;
+                if (args.getBoolean(1)) {
+                    jsWrapper = String.format("(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%s; d.head.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
+                } else {
+                    jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document)";
+                }
+                injectDeferredObject(args.getString(0), jsWrapper);
             }
             else {
-                status = PluginResult.Status.INVALID_ACTION;
+                return false;
             }
-            PluginResult pluginResult = new PluginResult(status, result);
-            pluginResult.setKeepCallback(true);
-            this.callbackContext.sendPluginResult(pluginResult);
         } catch (JSONException e) {
             this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
         }
@@ -179,6 +195,37 @@ public class InAppBrowser extends CordovaPlugin {
     }
 
     /**
+     * Inject an object (script or style) into the InAppBrowser WebView.
+     *
+     * This is a helper method for the inject{Script|Style}{Code|File} API calls, which
+     * provides a consistent method for injecting JavaScript code into the document.
+     *
+     * If a wrapper string is supplied, then the source string will be JSON-encoded (adding
+     * quotes) and wrapped using string formatting. (The wrapper string should have a single
+     * '%s' marker)
+     *
+     * @param source      The source object (filename or script/style text) to inject into
+     *                    the document.
+     * @param jsWrapper   A JavaScript string to wrap the source string in, so that the object
+     *                    is properly injected, or null if the source string is JavaScript text
+     *                    which should be executed directly.
+     */
+    private void injectDeferredObject(String source, String jsWrapper) {
+        String scriptToInject;
+        if (jsWrapper != null) {
+            org.json.JSONArray jsonEsc = new org.json.JSONArray();
+            jsonEsc.put(source);
+            String jsonRepr = jsonEsc.toString();
+            String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
+            scriptToInject = String.format(jsWrapper, jsonSourceString);
+        } else {
+            scriptToInject = source;
+        }
+        // This action will have the side-effect of blurring the currently focused element
+        this.inAppWebView.loadUrl("javascript:" + scriptToInject);
+    }
+
+    /**
      * Put the list of features into a hash map
      * 
      * @param optString
@@ -444,7 +491,7 @@ public class InAppBrowser extends CordovaPlugin {
                 // WebView
                 inAppWebView = new WebView(cordova.getActivity());
                 inAppWebView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
-                inAppWebView.setWebChromeClient(new InAppChromeClient());
+                inAppWebView.setWebChromeClient(new InAppChromeClient(thatWebView));
                 WebViewClient client = new InAppBrowserClient(thatWebView, edittext);
                 inAppWebView.setWebViewClient(client);
                 WebSettings settings = inAppWebView.getSettings();
@@ -527,8 +574,15 @@ public class InAppBrowser extends CordovaPlugin {
         result.setKeepCallback(keepCallback);
         this.callbackContext.sendPluginResult(result);
     }
+
     public class InAppChromeClient extends WebChromeClient {
 
+        private CordovaWebView webView;
+
+        public InAppChromeClient(CordovaWebView webView) {
+            super();
+            this.webView = webView;
+        }
         /**
          * Handle database quota exceeded notification.
          *
@@ -571,6 +625,57 @@ public class InAppBrowser extends CordovaPlugin {
             super.onGeolocationPermissionsShowPrompt(origin, callback);
             callback.invoke(origin, true, false);
         }
+
+        /**
+         * Tell the client to display a prompt dialog to the user.
+         * If the client returns true, WebView will assume that the client will
+         * handle the prompt dialog and call the appropriate JsPromptResult method.
+         *
+         * The prompt bridge provided for the InAppBrowser is capable of executing any
+         * oustanding callback belonging to the InAppBrowser plugin. Care has been
+         * taken that other callbacks cannot be triggered, and that no other code
+         * execution is possible.
+         *
+         * To trigger the bridge, the prompt default value should be of the form:
+         *
+         * gap-iab://<callbackId>
+         *
+         * where <callbackId> is the string id of the callback to trigger (something
+         * like "InAppBrowser0123456789")
+         *
+         * If present, the prompt message is expected to be a JSON-encoded value to
+         * pass to the callback. A JSON_EXCEPTION is returned if the JSON is invalid.
+         *
+         * @param view
+         * @param url
+         * @param message
+         * @param defaultValue
+         * @param result
+         */
+        @Override
+        public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
+            // See if the prompt string uses the 'gap-iab' protocol. If so, the remainder should be the id of a callback to execute.
+            if (defaultValue != null && defaultValue.startsWith("gap-iab://")) {
+                PluginResult scriptResult;
+                String scriptCallbackId = defaultValue.substring(10);
+                if (scriptCallbackId.startsWith("InAppBrowser")) {
+                    if(message == null || message.length() == 0) {
+                        scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray());
+                    } else {
+                        try {
+                            scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray(message));
+                        } catch(JSONException e) {
+                            scriptResult = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
+                        }
+                    }
+                    this.webView.sendPluginResult(scriptResult, scriptCallbackId);
+                    result.confirm("");
+                    return true;
+                }
+            }
+            return false;
+        }
+
     }
     
     /**

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java b/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
index ea684a4..8a13213 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
@@ -50,13 +50,10 @@ public class NativeToJsMessageQueue {
     // exec() is asynchronous. Set this to true when running bridge benchmarks.
     static final boolean DISABLE_EXEC_CHAINING = false;
     
-    // Upper limit for how much data to send to JS in one shot.
-    // TODO(agrieve): This is currently disable. It should be re-enabled once we
-    // remove support for returning values from exec() calls. This was
-    // deprecated in 2.2.0.
-    // Also, this currently only chops up on message boundaries. It may be useful
+    // Arbitrarily chosen upper limit for how much data to send to JS in one shot.
+    // This currently only chops up on message boundaries. It may be useful
     // to allow it to break up messages.
-    private static int MAX_PAYLOAD_SIZE = -1; //50 * 1024 * 10240;
+    private static int MAX_PAYLOAD_SIZE = 50 * 1024 * 10240;
     
     /**
      * The index into registeredListeners to treat as active. 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/api/Plugin.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/Plugin.java b/lib/cordova-android/framework/src/org/apache/cordova/api/Plugin.java
deleted file mode 100755
index 72171f2..0000000
--- a/lib/cordova-android/framework/src/org/apache/cordova/api/Plugin.java
+++ /dev/null
@@ -1,177 +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.apache.cordova.api;
-
-import org.apache.cordova.CordovaWebView;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * Legacy Plugin class. This acts as a shim to support the old execute() signature.
- * New plugins should extend CordovaPlugin directly.
- */
-@Deprecated
-public abstract class Plugin extends CordovaPlugin {
-    public LegacyContext    ctx;			        // LegacyContext object
-
-    public abstract PluginResult execute(String action, JSONArray args, String callbackId);
-
-    public boolean isSynch(String action) {
-        return false;
-    }
-    
-    @Override
-    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
-        super.initialize(cordova, webView);
-        this.setContext(cordova);
-        this.setView(webView);
-    }
-
-    /**
-     * Sets the context of the Plugin. This can then be used to do things like
-     * get file paths associated with the Activity.
-     *
-     * @param ctx The context of the main Activity.
-     */
-    public void setContext(CordovaInterface ctx) {
-        this.cordova = ctx;
-        this.ctx = new LegacyContext(cordova);
-    }
-
-    /**
-     * Sets the main View of the application, this is the WebView within which
-     * a Cordova app runs.
-     *
-     * @param webView The Cordova WebView
-     */
-    public void setView(CordovaWebView webView) {
-        this.webView = webView;
-    }
-    
-    @Override
-    public boolean execute(final String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException {
-        final String callbackId = callbackContext.getCallbackId();
-        boolean runAsync = !isSynch(action);
-        if (runAsync) {
-            // Run this on a different thread so that this one can return back to JS
-            cordova.getThreadPool().execute(new Runnable() {
-                public void run() {
-                    PluginResult cr;
-                    try {
-                        cr = execute(action, args, callbackId);
-                    } catch (Throwable e) {
-                        cr = new PluginResult(PluginResult.Status.ERROR, e.getMessage());
-                    }
-                    sendPluginResult(cr, callbackId);
-                }
-            });
-        } else {
-            PluginResult cr = execute(action, args, callbackId);
-    
-            // Interpret a null response as NO_RESULT, which *does* clear the callbacks on the JS side.
-            if (cr == null) {
-                cr = new PluginResult(PluginResult.Status.NO_RESULT);
-            }
-            
-            callbackContext.sendPluginResult(cr);
-        }
-        return true;
-    }
-
-    /**
-     * Send generic JavaScript statement back to JavaScript.
-     * sendPluginResult() should be used instead where possible.
-     */
-    public void sendJavascript(String statement) {
-        this.webView.sendJavascript(statement);
-    }
-
-    /**
-     * Send generic JavaScript statement back to JavaScript.
-     */
-    public void sendPluginResult(PluginResult pluginResult, String callbackId) {
-        this.webView.sendPluginResult(pluginResult, callbackId);
-    }
-
-    /**
-     * Call the JavaScript success callback for this plugin.
-     *
-     * This can be used if the execute code for the plugin is asynchronous meaning
-     * that execute should return null and the callback from the async operation can
-     * call success(...) or error(...)
-     *
-     * @param pluginResult      The result to return.
-     * @param callbackId        The callback id used when calling back into JavaScript.
-     */
-    public void success(PluginResult pluginResult, String callbackId) {
-        this.webView.sendPluginResult(pluginResult, callbackId);
-    }
-
-    /**
-     * Helper for success callbacks that just returns the Status.OK by default
-     *
-     * @param message           The message to add to the success result.
-     * @param callbackId        The callback id used when calling back into JavaScript.
-     */
-    public void success(JSONObject message, String callbackId) {
-        this.webView.sendPluginResult(new PluginResult(PluginResult.Status.OK, message), callbackId);
-    }
-
-    /**
-     * Helper for success callbacks that just returns the Status.OK by default
-     *
-     * @param message           The message to add to the success result.
-     * @param callbackId        The callback id used when calling back into JavaScript.
-     */
-    public void success(String message, String callbackId) {
-        this.webView.sendPluginResult(new PluginResult(PluginResult.Status.OK, message), callbackId);
-    }
-
-    /**
-     * Call the JavaScript error callback for this plugin.
-     *
-     * @param pluginResult      The result to return.
-     * @param callbackId        The callback id used when calling back into JavaScript.
-     */
-    public void error(PluginResult pluginResult, String callbackId) {
-        this.webView.sendPluginResult(pluginResult, callbackId);
-    }
-
-    /**
-     * Helper for error callbacks that just returns the Status.ERROR by default
-     *
-     * @param message           The message to add to the error result.
-     * @param callbackId        The callback id used when calling back into JavaScript.
-     */
-    public void error(JSONObject message, String callbackId) {
-        this.webView.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message), callbackId);
-    }
-
-    /**
-     * Helper for error callbacks that just returns the Status.ERROR by default
-     *
-     * @param message           The message to add to the error result.
-     * @param callbackId        The callback id used when calling back into JavaScript.
-     */
-    public void error(String message, String callbackId) {
-        this.webView.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, message), callbackId);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java b/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
index 774b21c..7d823cd 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
@@ -119,6 +119,7 @@ public class PluginManager {
                     service = xml.getAttributeValue(null, "name");
                     pluginClass = xml.getAttributeValue(null, "value");
                     // System.out.println("Plugin: "+name+" => "+value);
+                    Log.d(TAG, "<plugin> tags are deprecated, please use <features> instead. <plugin> will no longer work as of Cordova 3.0");
                     onload = "true".equals(xml.getAttributeValue(null, "onload"));
                     entry = new PluginEntry(service, pluginClass, onload);
                     this.addService(entry);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-blackberry/.gitignore
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/.gitignore b/lib/cordova-blackberry/.gitignore
new file mode 100644
index 0000000..a67abe6
--- /dev/null
+++ b/lib/cordova-blackberry/.gitignore
@@ -0,0 +1,26 @@
+# OS X
+
+.DS_Store
+
+# Eclipse
+
+deliverables/
+.preprocessed/
+
+# Text Editor Tmp
+
+._*
+
+# Generated libraries
+
+build/
+dist/
+bin/node_modules
+bin/templates/project/lib
+example/
+
+# OS X
+
+.DS_Store
+
+tags

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-blackberry/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/VERSION b/lib/cordova-blackberry/VERSION
index e70b452..59b7056 100644
--- a/lib/cordova-blackberry/VERSION
+++ b/lib/cordova-blackberry/VERSION
@@ -1 +1 @@
-2.6.0
+2.7.0rc1

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-blackberry/bin/create
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/create b/lib/cordova-blackberry/bin/create
index b7e719b..54903b8 100755
--- a/lib/cordova-blackberry/bin/create
+++ b/lib/cordova-blackberry/bin/create
@@ -25,11 +25,15 @@ set -e
 
 if [ -n "$1" ] && [ "$1" == "-h" ]
 then
-    echo 'usage: create path package appname'
-    echo 'After you have created your application, make sure to customize the project.properties file inside your app directory with your environment specifics!'
-    exit 0
+  echo "Usage: $0 <path_to_new_project> <package_name> <project_name>"
+  echo "    <path_to_new_project>: Path to your new Cordova iOS project"
+  echo "    <package_name>: Package name, following reverse-domain style convention (ignored on BlackBerry platforms)"
+  echo "    <project_name>: Project name"
+  echo 'After you have created your application, make sure to customize the project.properties file inside your app directory with your environment specifics!'
+  exit 0;
 fi
 
+
 BUILD_PATH="$( cd "$( dirname "$0" )/.." && pwd )"
 VERSION=$(cat "$BUILD_PATH/VERSION")
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-blackberry/bin/templates/project/lib/ant-contrib/ant-contrib-1.0b3.jar
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/lib/ant-contrib/ant-contrib-1.0b3.jar b/lib/cordova-blackberry/bin/templates/project/lib/ant-contrib/ant-contrib-1.0b3.jar
deleted file mode 100644
index 0625376..0000000
Binary files a/lib/cordova-blackberry/bin/templates/project/lib/ant-contrib/ant-contrib-1.0b3.jar and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-blackberry/bin/templates/project/www/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/www/VERSION b/lib/cordova-blackberry/bin/templates/project/www/VERSION
index e70b452..59b7056 100644
--- a/lib/cordova-blackberry/bin/templates/project/www/VERSION
+++ b/lib/cordova-blackberry/bin/templates/project/www/VERSION
@@ -1 +1 @@
-2.6.0
+2.7.0rc1

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-blackberry/bin/templates/project/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/www/index.html b/lib/cordova-blackberry/bin/templates/project/www/index.html
index 4d39cf3..a56d963 100644
--- a/lib/cordova-blackberry/bin/templates/project/www/index.html
+++ b/lib/cordova-blackberry/bin/templates/project/www/index.html
@@ -33,7 +33,7 @@
                 <p class="event received">Device is Ready</p>
             </div>
         </div>
-        <script type="text/javascript" src="cordova-2.6.0.js"></script>
+        <script type="text/javascript" src="cordova-2.7.0rc1.js"></script>
         <script type="text/javascript" src="js/index.js"></script>
         <script type="text/javascript">
             app.initialize();

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java
index af39a49..c332cc4 100644
--- a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java
@@ -54,7 +54,7 @@ public final class Device extends Plugin {
 				JSONObject device = new JSONObject();
 				device.put( FIELD_PLATFORM, "BlackBerry");
 				device.put( FIELD_UUID, new Integer( DeviceInfo.getDeviceId()) );
-				device.put( FIELD_CORDOVA, "2.6.0" );
+				device.put( FIELD_CORDOVA, "2.7.0rc1" );
 				device.put( FIELD_MODEL, new String(DeviceInfo.getDeviceName()) );
 				device.put( FIELD_NAME, new String(DeviceInfo.getDeviceName()) );
 				device.put( FIELD_VERSION, new String(DeviceInfo.getSoftwareVersion()) );

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-blackberry/javascript/cordova.blackberry.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/javascript/cordova.blackberry.js b/lib/cordova-blackberry/javascript/cordova.blackberry.js
index 86b9e8b..cd5878b 100644
--- a/lib/cordova-blackberry/javascript/cordova.blackberry.js
+++ b/lib/cordova-blackberry/javascript/cordova.blackberry.js
@@ -1,8 +1,8 @@
 // Platform: blackberry
 
-// commit 125dca530923a44a8f44f68f5e1970cbdd4e7faf
+// commit 4808bdada2a73c3fb2ec69857b8e970414c31d57
 
-// File generated at :: Wed Apr 03 2013 15:26:44 GMT-0700 (PDT)
+// File generated at :: Fri Apr 19 2013 14:51:35 GMT-0700 (PDT)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -219,6 +219,10 @@ var cordova = {
             }
             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);
             }
@@ -742,6 +746,7 @@ channel.createSticky('onDestroy');
 // Channels that must fire before "deviceready" is fired.
 channel.waitForInitialization('onCordovaReady');
 channel.waitForInitialization('onCordovaConnectionReady');
+channel.waitForInitialization('onDOMContentLoaded');
 
 module.exports = channel;
 
@@ -2222,7 +2227,7 @@ function initRead(reader, file) {
 
     if (typeof file == 'string') {
         // Deprecated in Cordova 2.4.
-        console.warning('Using a string argument with FileReader.readAs functions is deprecated.');
+        console.warn('Using a string argument with FileReader.readAs functions is deprecated.');
         reader._fileName = file;
     } else if (typeof file.fullPath == 'string') {
         reader._fileName = file.fullPath;
@@ -2580,7 +2585,7 @@ function getBasicAuthHeader(urlString) {
         var origin = protocol + url.host;
 
         // check whether there are the username:password credentials in the url
-        if (url.href.indexOf(origin) != 0) { // credentials found
+        if (url.href.indexOf(origin) !== 0) { // credentials found
             var atIndex = url.href.indexOf("@");
             credentials = url.href.substring(protocol.length, atIndex);
         }
@@ -2629,15 +2634,11 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
     var params = null;
     var chunkedMode = true;
     var headers = null;
-
+    var httpMethod = null;
     var basicAuthHeader = getBasicAuthHeader(server);
     if (basicAuthHeader) {
-        if (!options) {
-            options = new FileUploadOptions();
-        }
-        if (!options.headers) {
-            options.headers = {};
-        }
+        options = options || {};
+        options.headers = options.headers || {};
         options.headers[basicAuthHeader.name] = basicAuthHeader.value;
     }
 
@@ -2646,6 +2647,12 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
         fileName = options.fileName;
         mimeType = options.mimeType;
         headers = options.headers;
+        httpMethod = options.httpMethod || "POST";
+        if (httpMethod.toUpperCase() == "PUT"){
+            httpMethod = "PUT";
+        } else {
+            httpMethod = "POST";
+        }
         if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") {
             chunkedMode = options.chunkedMode;
         }
@@ -2672,7 +2679,7 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
             successCallback && successCallback(result);
         }
     };
-    exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id]);
+    exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]);
 };
 
 /**
@@ -2690,12 +2697,8 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
 
     var basicAuthHeader = getBasicAuthHeader(source);
     if (basicAuthHeader) {
-        if (!options) {
-            options = {};
-        }
-        if (!options.headers) {
-            options.headers = {};
-        }
+        options = options || {};
+        options.headers = options.headers || {};
         options.headers[basicAuthHeader.name] = basicAuthHeader.value;
     }
 
@@ -2734,12 +2737,11 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
 };
 
 /**
- * Aborts the ongoing file transfer on this object
- * @param successCallback {Function}  Callback to be invoked upon success
- * @param errorCallback {Function}    Callback to be invoked upon error
+ * Aborts the ongoing file transfer on this object. The original error
+ * callback for the file transfer will be called if necessary.
  */
-FileTransfer.prototype.abort = function(successCallback, errorCallback) {
-    exec(successCallback, errorCallback, 'FileTransfer', 'abort', [this._id]);
+FileTransfer.prototype.abort = function() {
+    exec(null, null, 'FileTransfer', 'abort', [this._id]);
 };
 
 module.exports = FileTransfer;
@@ -2783,12 +2785,13 @@ define("cordova/plugin/FileUploadOptions", function(require, exports, module) {
  * @param headers {Object}   Keys are header names, values are header values. Multiple
  *                           headers of the same name are not supported.
  */
-var FileUploadOptions = function(fileKey, fileName, mimeType, params, headers) {
+var FileUploadOptions = function(fileKey, fileName, mimeType, params, headers, httpMethod) {
     this.fileKey = fileKey || null;
     this.fileName = fileName || null;
     this.mimeType = mimeType || null;
     this.params = params || null;
     this.headers = headers || null;
+    this.httpMethod = httpMethod || null;
 };
 
 module.exports = FileUploadOptions;
@@ -3123,6 +3126,7 @@ define("cordova/plugin/InAppBrowser", function(require, exports, module) {
 
 var exec = require('cordova/exec');
 var channel = require('cordova/channel');
+var modulemapper = require('cordova/modulemapper');
 
 function InAppBrowser() {
    this.channels = {
@@ -3151,6 +3155,26 @@ InAppBrowser.prototype = {
         if (eventname in this.channels) {
             this.channels[eventname].unsubscribe(f);
         }
+    },
+
+    executeScript: function(injectDetails, cb) {
+        if (injectDetails.code) {
+            exec(cb, null, "InAppBrowser", "injectScriptCode", [injectDetails.code, !!cb]);
+        } else if (injectDetails.file) {
+            exec(cb, null, "InAppBrowser", "injectScriptFile", [injectDetails.file, !!cb]);
+        } else {
+            throw new Error('executeScript requires exactly one of code or file to be specified');
+        }
+    },
+
+    insertCSS: function(injectDetails, cb) {
+        if (injectDetails.code) {
+            exec(cb, null, "InAppBrowser", "injectStyleCode", [injectDetails.code, !!cb]);
+        } else if (injectDetails.file) {
+            exec(cb, null, "InAppBrowser", "injectStyleFile", [injectDetails.file, !!cb]);
+        } else {
+            throw new Error('insertCSS requires exactly one of code or file to be specified');
+        }
     }
 };
 
@@ -3159,6 +3183,13 @@ module.exports = function(strUrl, strWindowName, strWindowFeatures) {
     var cb = function(eventname) {
        iab._eventHandler(eventname);
     };
+
+    // Don't catch calls that write to existing frames (e.g. named iframes).
+    if (window.frames && window.frames[strWindowName]) {
+        var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open');
+        return origOpenFunc.apply(window, arguments);
+    }
+
     exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
     return iab;
 };
@@ -5361,7 +5392,7 @@ module.exports = {
                     model: "PlayBook",
                     name: "PlayBook", // deprecated: please use device.model
                     uuid: info.uuid,
-                    cordova: "2.6.0"
+                    cordova: "2.7.0rc1"
                 });
             }),
             request = new blackberry.transport.RemoteFunctionCall("org/apache/cordova/getDeviceInfo");
@@ -6018,7 +6049,7 @@ console.debug = function() {
 console.assert = function(expression) {
     if (expression) return;
 
-    var message = utils.vformat(arguments[1], [].slice.call(arguments, 2));
+    var message = logger.format.apply(logger.format, [].slice.call(arguments, 1));
     console.log("ASSERT: " + message);
 };
 
@@ -8669,10 +8700,10 @@ function logWithArgs(level, args) {
  * Parameters passed after message are used applied to
  * the message with utils.format()
  */
-logger.logLevel = function(level, message /* , ... */) {
+logger.logLevel = function(level /* , ... */) {
     // format the message with the parameters
-    var formatArgs = [].slice.call(arguments, 2);
-    message    = utils.vformat(message, formatArgs);
+    var formatArgs = [].slice.call(arguments, 1);
+    var message    = logger.format.apply(logger.format, formatArgs);
 
     if (LevelsMap[level] === null) {
         throw new Error("invalid logging level: " + level);
@@ -8707,6 +8738,92 @@ logger.logLevel = function(level, message /* , ... */) {
     }
 };
 
+
+/**
+ * Formats a string and arguments following it ala console.log()
+ *
+ * Any remaining arguments will be appended to the formatted string.
+ *
+ * for rationale, see FireBug's Console API:
+ *    http://getfirebug.com/wiki/index.php/Console_API
+ */
+logger.format = function(formatString, args) {
+    return __format(arguments[0], [].slice.call(arguments,1)).join(' ');
+};
+
+
+//------------------------------------------------------------------------------
+/**
+ * Formats a string and arguments following it ala vsprintf()
+ *
+ * format chars:
+ *   %j - format arg as JSON
+ *   %o - format arg as JSON
+ *   %c - format arg as ''
+ *   %% - replace with '%'
+ * any other char following % will format it's
+ * arg via toString().
+ *
+ * Returns an array containing the formatted string and any remaining
+ * arguments.
+ */
+function __format(formatString, args) {
+    if (formatString === null || formatString === undefined) return [""];
+    if (arguments.length == 1) return [formatString.toString()];
+
+    if (typeof formatString != "string")
+        formatString = formatString.toString();
+
+    var pattern = /(.*?)%(.)(.*)/;
+    var rest    = formatString;
+    var result  = [];
+
+    while (args.length) {
+        var match = pattern.exec(rest);
+        if (!match) break;
+
+        var arg   = args.shift();
+        rest = match[3];
+        result.push(match[1]);
+
+        if (match[2] == '%') {
+            result.push('%');
+            args.unshift(arg);
+            continue;
+        }
+
+        result.push(__formatted(arg, match[2]));
+    }
+
+    result.push(rest);
+
+    var remainingArgs = [].slice.call(args);
+    remainingArgs.unshift(result.join(''));
+    return remainingArgs;
+}
+
+function __formatted(object, formatChar) {
+
+    try {
+        switch(formatChar) {
+            case 'j':
+            case 'o': return JSON.stringify(object);
+            case 'c': return '';
+        }
+    }
+    catch (e) {
+        return "error JSON.stringify()ing argument: " + e;
+    }
+
+    if ((object === null) || (object === undefined)) {
+        return Object.prototype.toString.call(object);
+    }
+
+    return object.toString();
+}
+
+
+//------------------------------------------------------------------------------
 // when deviceready fires, log queued messages
 logger.__onDeviceReady = function() {
     if (DeviceReady) return;
@@ -8875,13 +8992,13 @@ module.exports = {
             console.log("Notification.confirm(string, function, string, string) is deprecated.  Use Notification.confirm(string, function, string, array).");
         }
 
-        // Android and iOS take an array of button label names.
+        // Some platforms take an array of button label names.
         // Other platforms take a comma separated list.
         // For compatibility, we convert to the desired type based on the platform.
-        if (platform.id == "android" || platform.id == "ios") {
+        if (platform.id == "android" || platform.id == "ios" || platform.id == "windowsphone") {
             if (typeof _buttonLabels === 'string') {
                 var buttonLabelString = _buttonLabels;
-                _buttonLabels = buttonLabelString.split(",");
+                _buttonLabels = _buttonLabels.split(","); // not crazy about changing the var type here
             }
         } else {
             if (Array.isArray(_buttonLabels)) {
@@ -9290,7 +9407,7 @@ module.exports = {
             model: "Dev Alpha",
             name: "Dev Alpha", // deprecated: please use device.model
             uuid: blackberry.identity.uuid,
-            cordova: "2.6.0"
+            cordova: "2.7.0rc1"
         });
 
         return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "Device info returned" };
@@ -9303,6 +9420,7 @@ module.exports = {
 define("cordova/plugin/qnx/file", function(require, exports, module) {
 
 /*global WebKitBlobBuilder:false */
+/*global Blob:false */
 var cordova = require('cordova'),
     FileError = require('cordova/plugin/FileError'),
     DirectoryEntry = require('cordova/plugin/DirectoryEntry'),
@@ -9710,6 +9828,7 @@ module.exports = {
 // file: lib/blackberry/plugin/qnx/fileTransfer.js
 define("cordova/plugin/qnx/fileTransfer", function(require, exports, module) {
 
+/*global Blob:false */
 var cordova = require('cordova'),
     FileEntry = require('cordova/plugin/FileEntry'),
     FileTransferError = require('cordova/plugin/FileTransferError'),
@@ -10566,62 +10685,6 @@ utils.alert = function(msg) {
     }
 };
 
-/**
- * Formats a string and arguments following it ala sprintf()
- *
- * see utils.vformat() for more information
- */
-utils.format = function(formatString /* ,... */) {
-    var args = [].slice.call(arguments, 1);
-    return utils.vformat(formatString, args);
-};
-
-/**
- * Formats a string and arguments following it ala vsprintf()
- *
- * format chars:
- *   %j - format arg as JSON
- *   %o - format arg as JSON
- *   %c - format arg as ''
- *   %% - replace with '%'
- * any other char following % will format it's
- * arg via toString().
- *
- * for rationale, see FireBug's Console API:
- *    http://getfirebug.com/wiki/index.php/Console_API
- */
-utils.vformat = function(formatString, args) {
-    if (formatString === null || formatString === undefined) return "";
-    if (arguments.length == 1) return formatString.toString();
-    if (typeof formatString != "string") return formatString.toString();
-
-    var pattern = /(.*?)%(.)(.*)/;
-    var rest    = formatString;
-    var result  = [];
-
-    while (args.length) {
-        var arg   = args.shift();
-        var match = pattern.exec(rest);
-
-        if (!match) break;
-
-        rest = match[3];
-
-        result.push(match[1]);
-
-        if (match[2] == '%') {
-            result.push('%');
-            args.unshift(arg);
-            continue;
-        }
-
-        result.push(formatted(arg, match[2]));
-    }
-
-    result.push(rest);
-
-    return result.join('');
-};
 
 //------------------------------------------------------------------------------
 function UUIDcreatePart(length) {
@@ -10636,26 +10699,6 @@ function UUIDcreatePart(length) {
     return uuidpart;
 }
 
-//------------------------------------------------------------------------------
-function formatted(object, formatChar) {
-
-    try {
-        switch(formatChar) {
-            case 'j':
-            case 'o': return JSON.stringify(object);
-            case 'c': return '';
-        }
-    }
-    catch (e) {
-        return "error JSON.stringify()ing argument: " + e;
-    }
-
-    if ((object === null) || (object === undefined)) {
-        return Object.prototype.toString.call(object);
-    }
-
-    return object.toString();
-}
 
 });
 
@@ -10665,6 +10708,25 @@ window.cordova = require('cordova');
 // file: lib/scripts/bootstrap.js
 
 (function (context) {
+    var channel = require('cordova/channel');
+    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) {
@@ -10686,8 +10748,6 @@ window.cordova = require('cordova');
         context.navigator = replaceNavigator(context.navigator);
     }
 
-    var channel = require("cordova/channel");
-
     // _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.
@@ -10696,29 +10756,26 @@ window.cordova = require('cordova');
     }
 
     /**
-     * Create all cordova objects once page has fully loaded and native side is ready.
+     * Create all cordova objects once native side is ready.
      */
     channel.join(function() {
-        var builder = require('cordova/builder'),
-            platform = require('cordova/platform');
-
-        builder.buildIntoButDoNotClobber(platform.defaults, context);
-        builder.buildIntoAndClobber(platform.clobbers, context);
-        builder.buildIntoAndMerge(platform.merges, context);
-
         // Call the platform-specific initialization
-        platform.initialize();
+        require('cordova/platform').initialize();
 
         // Fire event to notify that all objects are created
         channel.onCordovaReady.fire();
 
-        // Fire onDeviceReady event once all constructors have run and
-        // cordova info has been received from native side.
+        // Fire onDeviceReady event once page has fully loaded, all
+        // constructors have run and cordova info has been received from native
+        // side.
+        // This join call is deliberately made after platform.initialize() in
+        // order that plugins may manipulate channel.deviceReadyChannelsArray
+        // if necessary.
         channel.join(function() {
             require('cordova').fireDocumentEvent('deviceready');
         }, channel.deviceReadyChannelsArray);
 
-    }, [ channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady ]);
+    }, platformInitChannelsArray);
 
 }(window));
 
@@ -10823,31 +10880,27 @@ document.addEventListener("DOMContentLoaded", function () {
         }
     }
 
+
     // Try to XHR the cordova_plugins.json file asynchronously.
-    try { // we commented we were going to try, so let us actually try and catch 
+    try { // we commented we were going to try, so let us actually try and catch
         var xhr = new context.XMLHttpRequest();
-        xhr.onreadystatechange = function() {
-            if (this.readyState != 4) { // not DONE
-                return;
-            }
-
+        xhr.onload = function() {
             // If the response is a JSON string which composes an array, call handlePluginsObject.
             // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
-            if (this.status == 200) {
-                var obj = JSON.parse(this.responseText);
-                if (obj && obj instanceof Array && obj.length > 0) {
-                    handlePluginsObject(obj);
-                } else {
-                    finishPluginLoading();
-                }
+            var obj = JSON.parse(this.responseText);
+            if (obj && obj instanceof Array && obj.length > 0) {
+                handlePluginsObject(obj);
             } else {
                 finishPluginLoading();
             }
         };
+        xhr.onerror = function() {
+            finishPluginLoading();
+        };
         xhr.open('GET', 'cordova_plugins.json', true); // Async
         xhr.send();
     }
-    catch(err) {
+    catch(err){
         finishPluginLoading();
     }
 }(window));

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/.gitignore
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/.gitignore b/lib/cordova-ios/.gitignore
new file mode 100644
index 0000000..e0ac686
--- /dev/null
+++ b/lib/cordova-ios/.gitignore
@@ -0,0 +1,12 @@
+.DS_Store
+.*.sw?
+*.cso
+tmp
+*.mode1v3
+*.pbxuser
+build
+*.xcworkspace
+xcuserdata
+CordovaLib/javascript/cordova-*.js
+CordovaLib/CordovaLibApp/www/cordova.ios.js
+console.log
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/.gitmodules
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/.gitmodules b/lib/cordova-ios/.gitmodules
new file mode 100644
index 0000000..3625844
--- /dev/null
+++ b/lib/cordova-ios/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "PhoneGapLibTest/www"]
+	path = PhoneGapLibTest/www
+	url = git://github.com/phonegap/mobile-spec.git

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDV.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDV.h b/lib/cordova-ios/CordovaLib/Classes/CDV.h
index 5a0ae6a..15d9316 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDV.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDV.h
@@ -33,7 +33,6 @@
 #import "CDVContact.h"
 #import "CDVContacts.h"
 #import "CDVDebug.h"
-#import "CDVDebugConsole.h"
 #import "CDVDevice.h"
 #import "CDVFile.h"
 #import "CDVFileTransfer.h"
@@ -47,6 +46,7 @@
 #import "CDVLocalStorage.h"
 #import "CDVInAppBrowser.h"
 #import "CDVScreenOrientationDelegate.h"
+#import "CDVTimer.h"
 
 #import "NSArray+Comparisons.h"
 #import "NSData+Base64.h"

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h b/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
index 947ae2d..b288522 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
@@ -40,6 +40,7 @@
 #define __CORDOVA_2_4_0 20400
 #define __CORDOVA_2_5_0 20500
 #define __CORDOVA_2_6_0 20600
+#define __CORDOVA_2_7_0 20700
 #define __CORDOVA_NA 99999      /* not available */
 
 /*
@@ -50,7 +51,7 @@
  #endif
  */
 #ifndef CORDOVA_VERSION_MIN_REQUIRED
-    #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_2_6_0
+    #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_2_7_0
 #endif
 
 /*

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVDebugConsole.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVDebugConsole.h b/lib/cordova-ios/CordovaLib/Classes/CDVDebugConsole.h
deleted file mode 100644
index 6a0a185..0000000
--- a/lib/cordova-ios/CordovaLib/Classes/CDVDebugConsole.h
+++ /dev/null
@@ -1,28 +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.
- */
-
-#import <Foundation/Foundation.h>
-#import <UIKit/UIKit.h>
-#import "CDVPlugin.h"
-
-@interface CDVDebugConsole : CDVPlugin {}
-
-- (void)log:(CDVInvokedUrlCommand*)command;
-
-@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVDebugConsole.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVDebugConsole.m b/lib/cordova-ios/CordovaLib/Classes/CDVDebugConsole.m
deleted file mode 100644
index 29cbb91..0000000
--- a/lib/cordova-ios/CordovaLib/Classes/CDVDebugConsole.m
+++ /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.
- */
-
-#import "CDVDebugConsole.h"
-
-@implementation CDVDebugConsole
-
-- (void)log:(CDVInvokedUrlCommand*)command
-{
-    NSString* message = [command.arguments objectAtIndex:0];
-    NSDictionary* options = [command.arguments objectAtIndex:1];
-    NSString* log_level = @"INFO";
-
-    if ([options objectForKey:@"logLevel"]) {
-        log_level = [options objectForKey:@"logLevel"];
-    }
-
-    NSLog(@"[%@] %@", log_level, message);
-}
-
-@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFile.m b/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
index 8c65270..10908ce 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
@@ -227,10 +227,9 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
     NSURL* testUri = [NSURL URLWithString:strUri];
     CDVPluginResult* result = nil;
 
-    if (!testUri || ![testUri isFileURL]) {
-        // issue ENCODING_ERR
+    if (!testUri) {
         result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR];
-    } else {
+    } else if ([testUri isFileURL]) {
         NSFileManager* fileMgr = [[NSFileManager alloc] init];
         NSString* path = [testUri path];
         // NSLog(@"url path: %@", path);
@@ -262,7 +261,13 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
             // return NOT_FOUND_ERR
             result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
         }
+    } else if ([strUri hasPrefix:@"assets-library://"]) {
+        NSDictionary* fileSystem = [self getDirectoryEntry:strUri isDirectory:NO];
+        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem];
+    } else {
+        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:ENCODING_ERR];
     }
+
     if (result != nil) {
         [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
     }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
index d82cdd3..233a114 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
@@ -53,10 +53,15 @@ extern NSString* const kOptionsKeyCookie;
                                   AndHttpStatus:(int)httpStatus
                                         AndBody:(NSString*)body;
 @property (readonly) NSMutableDictionary* activeTransfers;
+@property (nonatomic, assign) UIBackgroundTaskIdentifier backgroundTaskID;
 @end
 
+@class CDVFileTransferEntityLengthRequest;
+
 @interface CDVFileTransferDelegate : NSObject {}
 
+- (void)updateBytesExpected:(NSInteger)newBytesExpected;
+
 @property (strong) NSMutableData* responseData; // atomic
 @property (nonatomic, strong) CDVFileTransfer* command;
 @property (nonatomic, assign) CDVFileTransferDirection direction;
@@ -70,5 +75,7 @@ extern NSString* const kOptionsKeyCookie;
 @property (nonatomic, assign) NSInteger bytesTransfered;
 @property (nonatomic, assign) NSInteger bytesExpected;
 @property (nonatomic, assign) BOOL trustAllHosts;
+@property (strong) NSFileHandle* targetFileHandle;
+@property (nonatomic, strong) CDVFileTransferEntityLengthRequest* entityLengthRequest;
 
 @end;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
index 5741aca..5536715 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
@@ -126,17 +126,19 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     // arguments order from js: [filePath, server, fileKey, fileName, mimeType, params, debug, chunkedMode]
     // however, params is a JavaScript object and during marshalling is put into the options dict,
     // thus debug and chunkedMode are the 6th and 7th arguments
-    NSArray* arguments = command.arguments;
-    NSString* target = (NSString*)[arguments objectAtIndex:0];
-    NSString* server = (NSString*)[arguments objectAtIndex:1];
-    NSString* fileKey = [arguments objectAtIndex:2 withDefault:@"file"];
-    NSString* fileName = [arguments objectAtIndex:3 withDefault:@"no-filename"];
-    NSString* mimeType = [arguments objectAtIndex:4 withDefault:nil];
-    NSDictionary* options = [arguments objectAtIndex:5 withDefault:nil];
+    NSString* target = [command argumentAtIndex:0];
+    NSString* server = [command argumentAtIndex:1];
+    NSString* fileKey = [command argumentAtIndex:2 withDefault:@"file"];
+    NSString* fileName = [command argumentAtIndex:3 withDefault:@"no-filename"];
+    NSString* mimeType = [command argumentAtIndex:4 withDefault:nil];
+    NSDictionary* options = [command argumentAtIndex:5 withDefault:nil];
     //    BOOL trustAllHosts = [[arguments objectAtIndex:6 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs
-    BOOL chunkedMode = [[arguments objectAtIndex:7 withDefault:[NSNumber numberWithBool:YES]] boolValue];
-    NSDictionary* headers = [arguments objectAtIndex:8 withDefault:nil];
-
+    BOOL chunkedMode = [[command argumentAtIndex:7 withDefault:[NSNumber numberWithBool:YES]] boolValue];
+    NSDictionary* headers = [command argumentAtIndex:8 withDefault:nil];
+    // Allow alternative http method, default to POST. JS side checks
+    // for allowed methods, currently PUT or POST (forces POST for
+    // unrecognised values)
+    NSString* httpMethod = [command argumentAtIndex:10 withDefault:@"POST"];
     CDVPluginResult* result = nil;
     CDVFileTransferError errorCode = 0;
 
@@ -158,7 +160,8 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     }
 
     NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url];
-    [req setHTTPMethod:@"POST"];
+
+    [req setHTTPMethod:httpMethod];
 
     //    Magic value to set a cookie
     if ([options objectForKey:kOptionsKeyCookie]) {
@@ -212,6 +215,12 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
         CFStreamCreateBoundPair(NULL, &readStream, &writeStream, kStreamBufferSize);
         [req setHTTPBodyStream:CFBridgingRelease(readStream)];
 
+        self.backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
+                [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskID];
+                self.backgroundTaskID = UIBackgroundTaskInvalid;
+                NSLog(@"Background task to upload media finished.");
+            }];
+
         [self.commandDelegate runInBackground:^{
             if (CFWriteStreamOpen(writeStream)) {
                 NSData* chunks[] = {postBodyBeforeFile, fileData, postBodyAfterFile};
@@ -456,19 +465,56 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
 
 @end
 
+@interface CDVFileTransferEntityLengthRequest : NSObject {
+    NSURLConnection* _connection;
+    CDVFileTransferDelegate* __weak _originalDelegate;
+}
+
+- (CDVFileTransferEntityLengthRequest*)initWithOriginalRequest:(NSURLRequest*)originalRequest andDelegate:(CDVFileTransferDelegate*)originalDelegate;
+
+@end;
+
+@implementation CDVFileTransferEntityLengthRequest;
+
+- (CDVFileTransferEntityLengthRequest*)initWithOriginalRequest:(NSURLRequest*)originalRequest andDelegate:(CDVFileTransferDelegate*)originalDelegate
+{
+    if (self) {
+        DLog(@"Requesting entity length for GZIPped content...");
+
+        NSMutableURLRequest* req = [originalRequest mutableCopy];
+        [req setHTTPMethod:@"HEAD"];
+        [req setValue:@"identity" forHTTPHeaderField:@"Accept-Encoding"];
+
+        _originalDelegate = originalDelegate;
+        _connection = [NSURLConnection connectionWithRequest:req delegate:self];
+    }
+    return self;
+}
+
+- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
+{
+    DLog(@"HEAD request returned; content-length is %lld", [response expectedContentLength]);
+    [_originalDelegate updateBytesExpected:[response expectedContentLength]];
+}
+
+- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
+{}
+
+- (void)connectionDidFinishLoading:(NSURLConnection*)connection
+{}
+
+@end
+
 @implementation CDVFileTransferDelegate
 
-@synthesize callbackId, connection, source, target, responseData, command, bytesTransfered, bytesExpected, direction, responseCode, objectId;
+@synthesize callbackId, connection = _connection, source, target, responseData, command, bytesTransfered, bytesExpected, direction, responseCode, objectId, targetFileHandle;
 
 - (void)connectionDidFinishLoading:(NSURLConnection*)connection
 {
     NSString* uploadResponse = nil;
     NSString* downloadResponse = nil;
-    BOOL downloadWriteOK = NO;
     NSMutableDictionary* uploadResult;
     CDVPluginResult* result = nil;
-    NSError* __autoreleasing error = nil;
-    NSString* parentPath;
     BOOL bDirRequest = NO;
     CDVFile* file;
 
@@ -491,40 +537,15 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
         }
     }
     if (self.direction == CDV_TRANSFER_DOWNLOAD) {
-        DLog(@"Write file %@", target);
-        // error=[[NSError alloc]init];
-
-        if ((self.responseCode >= 200) && (self.responseCode < 300)) {
-            @try {
-                parentPath = [self.target stringByDeletingLastPathComponent];
-
-                // check if the path exists => create directories if needed
-                if (![[NSFileManager defaultManager] fileExistsAtPath:parentPath]) {
-                    [[NSFileManager defaultManager] createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:nil];
-                }
-
-                downloadWriteOK = [self.responseData writeToFile:self.target options:NSDataWritingFileProtectionNone error:&error];
+        if (self.targetFileHandle) {
+            [self.targetFileHandle closeFile];
+            self.targetFileHandle = nil;
+            DLog(@"File Transfer Download success");
 
-                if (downloadWriteOK == NO) {
-                    // send our results back
-                    downloadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
-                    result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:INVALID_URL_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:downloadResponse]];
-                } else {
-                    DLog(@"File Transfer Download success");
-
-                    file = [[CDVFile alloc] init];
-
-                    result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[file getDirectoryEntry:target isDirectory:bDirRequest]];
-                }
-            }
-            @catch(id exception) {
-                // jump back to main thread
-                downloadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
-                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsDictionary:[command createFileTransferError:FILE_NOT_FOUND_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:downloadResponse]];
-            }
+            file = [[CDVFile alloc] init];
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[file getDirectoryEntry:target isDirectory:bDirRequest]];
         } else {
             downloadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
-
             result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:downloadResponse]];
         }
     }
@@ -533,11 +554,28 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
 
     // remove connection for activeTransfers
     [command.activeTransfers removeObjectForKey:objectId];
+
+    // remove background id task in case our upload was done in the background
+    [[UIApplication sharedApplication] endBackgroundTask:self.command.backgroundTaskID];
+    self.command.backgroundTaskID = UIBackgroundTaskInvalid;
+}
+
+- (void)cancelTransferWithError:(NSURLConnection*)connection errorMessage:(NSString*)errorMessage
+{
+    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsDictionary:[self.command createFileTransferError:FILE_NOT_FOUND_ERR AndSource:self.source AndTarget:self.target AndHttpStatus:self.responseCode AndBody:errorMessage]];
+
+    NSLog(@"File Transfer Error: %@", errorMessage);
+    [connection cancel];
+    [self.command.activeTransfers removeObjectForKey:self.objectId];
+    [self.command.commandDelegate sendPluginResult:result callbackId:callbackId];
 }
 
 - (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
 {
+    NSError* __autoreleasing error = nil;
+
     self.mimeType = [response MIMEType];
+    self.targetFileHandle = nil;
 
     // required for iOS 4.3, for some reason; response is
     // a plain NSURLResponse, not the HTTP subclass
@@ -546,6 +584,11 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
 
         self.responseCode = [httpResponse statusCode];
         self.bytesExpected = [response expectedContentLength];
+        if ((self.direction == CDV_TRANSFER_DOWNLOAD) && (self.responseCode == 200) && (self.bytesExpected == NSURLResponseUnknownLength)) {
+            // Kick off HEAD request to server to get real length
+            // bytesExpected will be updated when that response is returned
+            self.entityLengthRequest = [[CDVFileTransferEntityLengthRequest alloc] initWithOriginalRequest:connection.currentRequest andDelegate:self];
+        }
     } else if ([response.URL isFileURL]) {
         NSDictionary* attr = [[NSFileManager defaultManager] attributesOfItemAtPath:[response.URL path] error:nil];
         self.responseCode = 200;
@@ -554,6 +597,31 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
         self.responseCode = 200;
         self.bytesExpected = NSURLResponseUnknownLength;
     }
+    if ((self.direction == CDV_TRANSFER_DOWNLOAD) && (self.responseCode >= 200) && (self.responseCode < 300)) {
+        // Download response is okay; begin streaming output to file
+        NSString* parentPath = [self.target stringByDeletingLastPathComponent];
+
+        // create parent directories if needed
+        if ([[NSFileManager defaultManager] createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:&error] == NO) {
+            if (error) {
+                [self cancelTransferWithError:connection errorMessage:[NSString stringWithFormat:@"Could not create path to save downloaded file: %@", [error localizedDescription]]];
+            } else {
+                [self cancelTransferWithError:connection errorMessage:@"Could not create path to save downloaded file"];
+            }
+            return;
+        }
+        // create target file
+        if ([[NSFileManager defaultManager] createFileAtPath:self.target contents:nil attributes:nil] == NO) {
+            [self cancelTransferWithError:connection errorMessage:@"Could not create target file"];
+            return;
+        }
+        // open target file for writing
+        self.targetFileHandle = [NSFileHandle fileHandleForWritingAtPath:self.target];
+        if (self.targetFileHandle == nil) {
+            [self cancelTransferWithError:connection errorMessage:@"Could not open target file for writing"];
+        }
+        DLog(@"Streaming to file %@", target);
+    }
 }
 
 - (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
@@ -571,10 +639,30 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
 - (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
 {
     self.bytesTransfered += data.length;
-    [self.responseData appendData:data];
+    if (self.targetFileHandle) {
+        [self.targetFileHandle writeData:data];
+    } else {
+        [self.responseData appendData:data];
+    }
+    [self updateProgress];
+}
+
+- (void)updateBytesExpected:(NSInteger)newBytesExpected
+{
+    DLog(@"Updating bytesExpected to %d", newBytesExpected);
+    self.bytesExpected = newBytesExpected;
+    [self updateProgress];
+}
 
+- (void)updateProgress
+{
     if (self.direction == CDV_TRANSFER_DOWNLOAD) {
         BOOL lengthComputable = (self.bytesExpected != NSURLResponseUnknownLength);
+        // If the response is GZipped, and we have an outstanding HEAD request to get
+        // the length, then hold off on sending progress events.
+        if (!lengthComputable && (self.entityLengthRequest != nil)) {
+            return;
+        }
         NSMutableDictionary* downloadProgress = [NSMutableDictionary dictionaryWithCapacity:3];
         [downloadProgress setObject:[NSNumber numberWithBool:lengthComputable] forKey:@"lengthComputable"];
         [downloadProgress setObject:[NSNumber numberWithInt:self.bytesTransfered] forKey:@"loaded"];
@@ -618,6 +706,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
 {
     if ((self = [super init])) {
         self.responseData = [NSMutableData data];
+        self.targetFileHandle = nil;
     }
     return self;
 }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
index f63250a..343f40d 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
@@ -24,28 +24,21 @@
 
 @class CDVInAppBrowserViewController;
 
-@protocol CDVInAppBrowserNavigationDelegate <NSObject>
-
-- (void)browserLoadStart:(NSURL*)url;
-- (void)browserLoadStop:(NSURL*)url;
-- (void)browserLoadError:(NSError*)error forUrl:(NSURL*)url;
-- (void)browserExit;
-
-@end
-
-@interface CDVInAppBrowser : CDVPlugin <CDVInAppBrowserNavigationDelegate>
+@interface CDVInAppBrowser : CDVPlugin {
+    BOOL _injectedIframeBridge;
+}
 
 @property (nonatomic, retain) CDVInAppBrowserViewController* inAppBrowserViewController;
 @property (nonatomic, copy) NSString* callbackId;
 
 - (void)open:(CDVInvokedUrlCommand*)command;
 - (void)close:(CDVInvokedUrlCommand*)command;
+- (void)injectScriptCode:(CDVInvokedUrlCommand*)command;
 
 @end
 
 @interface CDVInAppBrowserViewController : UIViewController <UIWebViewDelegate>{
     @private
-    NSURL* _requestedURL;
     NSString* _userAgent;
     NSString* _prevUserAgent;
     NSInteger _userAgentLockToken;
@@ -61,7 +54,8 @@
 @property (nonatomic, strong) IBOutlet UIToolbar* toolbar;
 
 @property (nonatomic, weak) id <CDVScreenOrientationDelegate> orientationDelegate;
-@property (nonatomic, weak) id <CDVInAppBrowserNavigationDelegate> navigationDelegate;
+@property (nonatomic, weak) CDVInAppBrowser* navigationDelegate;
+@property (nonatomic) NSURL* requestedURL;
 
 - (void)close;
 - (void)navigateTo:(NSURL*)url;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
index d001dfd..f366bd8 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
@@ -20,6 +20,7 @@
 #import "CDVInAppBrowser.h"
 #import "CDVPluginResult.h"
 #import "CDVUserAgentUtil.h"
+#import "CDVJSON.h"
 
 #define    kInAppBrowserTargetSelf @"_self"
 #define    kInAppBrowserTargetSystem @"_system"
@@ -159,35 +160,161 @@
     }
 }
 
-#pragma mark CDVInAppBrowserNavigationDelegate
+// This is a helper method for the inject{Script|Style}{Code|File} API calls, which
+// provides a consistent method for injecting JavaScript code into the document.
+//
+// If a wrapper string is supplied, then the source string will be JSON-encoded (adding
+// quotes) and wrapped using string formatting. (The wrapper string should have a single
+// '%@' marker).
+//
+// If no wrapper is supplied, then the source string is executed directly.
 
-- (void)browserLoadStart:(NSURL*)url
+- (void)injectDeferredObject:(NSString*)source withWrapper:(NSString*)jsWrapper
 {
+    if (!_injectedIframeBridge) {
+        _injectedIframeBridge = YES;
+        // Create an iframe bridge in the new document to communicate with the CDVInAppBrowserViewController
+        [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:@"(function(d){var e = _cdvIframeBridge = d.createElement('iframe');e.style.display='none';d.body.appendChild(e);})(document)"];
+    }
+
+    if (jsWrapper != nil) {
+        NSString* sourceArrayString = [@[source] JSONString];
+        if (sourceArrayString) {
+            NSString* sourceString = [sourceArrayString substringWithRange:NSMakeRange(1, [sourceArrayString length] - 2)];
+            NSString* jsToInject = [NSString stringWithFormat:jsWrapper, sourceString];
+            [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:jsToInject];
+        }
+    } else {
+        [self.inAppBrowserViewController.webView stringByEvaluatingJavaScriptFromString:source];
+    }
+}
+
+- (void)injectScriptCode:(CDVInvokedUrlCommand*)command
+{
+    NSString* jsWrapper = nil;
+
+    if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) {
+        jsWrapper = [NSString stringWithFormat:@"_cdvIframeBridge.src='gap-iab://%@/'+window.escape(JSON.stringify([eval(%%@)]));", command.callbackId];
+    }
+    [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper];
+}
+
+- (void)injectScriptFile:(CDVInvokedUrlCommand*)command
+{
+    NSString* jsWrapper;
+
+    if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) {
+        jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('script'); c.src = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId];
+    } else {
+        jsWrapper = @"(function(d) { var c = d.createElement('script'); c.src = %@; d.body.appendChild(c); })(document)";
+    }
+    [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper];
+}
+
+- (void)injectStyleCode:(CDVInvokedUrlCommand*)command
+{
+    NSString* jsWrapper;
+
+    if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) {
+        jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('style'); c.innerHTML = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId];
+    } else {
+        jsWrapper = @"(function(d) { var c = d.createElement('style'); c.innerHTML = %@; d.body.appendChild(c); })(document)";
+    }
+    [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper];
+}
+
+- (void)injectStyleFile:(CDVInvokedUrlCommand*)command
+{
+    NSString* jsWrapper;
+
+    if ((command.callbackId != nil) && ![command.callbackId isEqualToString:@"INVALID"]) {
+        jsWrapper = [NSString stringWithFormat:@"(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%@; c.onload = function() { _cdvIframeBridge.src='gap-iab://%@'; }; d.body.appendChild(c); })(document)", command.callbackId];
+    } else {
+        jsWrapper = @"(function(d) { var c = d.createElement('link'); c.rel='stylesheet', c.type='text/css'; c.href = %@; d.body.appendChild(c); })(document)";
+    }
+    [self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper];
+}
+
+/**
+ * The iframe bridge provided for the InAppBrowser is capable of executing any oustanding callback belonging
+ * to the InAppBrowser plugin. Care has been taken that other callbacks cannot be triggered, and that no
+ * other code execution is possible.
+ *
+ * To trigger the bridge, the iframe (or any other resource) should attempt to load a url of the form:
+ *
+ * gap-iab://<callbackId>/<arguments>
+ *
+ * where <callbackId> is the string id of the callback to trigger (something like "InAppBrowser0123456789")
+ *
+ * If present, the path component of the special gap-iab:// url is expected to be a URL-escaped JSON-encoded
+ * value to pass to the callback. [NSURL path] should take care of the URL-unescaping, and a JSON_EXCEPTION
+ * is returned if the JSON is invalid.
+ */
+- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
+{
+    NSURL* url = request.URL;
+
+    // See if the url uses the 'gap-iab' protocol. If so, the host should be the id of a callback to execute,
+    // and the path, if present, should be a JSON-encoded value to pass to the callback.
+    if ([[url scheme] isEqualToString:@"gap-iab"]) {
+        NSString* scriptCallbackId = [url host];
+        CDVPluginResult* pluginResult = nil;
+
+        if ([scriptCallbackId hasPrefix:@"InAppBrowser"]) {
+            NSString* scriptResult = [url path];
+            NSError* __autoreleasing error = nil;
+
+            // The message should be a JSON-encoded array of the result of the script which executed.
+            if ((scriptResult != nil) && ([scriptResult length] > 1)) {
+                scriptResult = [scriptResult substringFromIndex:1];
+                NSData* decodedResult = [NSJSONSerialization JSONObjectWithData:[scriptResult dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error];
+                if ((error == nil) && [decodedResult isKindOfClass:[NSArray class]]) {
+                    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:(NSArray*)decodedResult];
+                } else {
+                    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_JSON_EXCEPTION];
+                }
+            } else {
+                pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:@[]];
+            }
+            [self.commandDelegate sendPluginResult:pluginResult callbackId:scriptCallbackId];
+            return NO;
+        }
+    }
+    return YES;
+}
+
+- (void)webViewDidStartLoad:(UIWebView*)theWebView
+{
+    _injectedIframeBridge = NO;
     if (self.callbackId != nil) {
+        NSString* url = [[self.inAppBrowserViewController requestedURL] absoluteString];
         CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
-                                                      messageAsDictionary:@{@"type":@"loadstart", @"url":[url absoluteString]}];
+                                                      messageAsDictionary:@{@"type":@"loadstart", @"url":url}];
         [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
 
         [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
     }
 }
 
-- (void)browserLoadStop:(NSURL*)url
+- (void)webViewDidFinishLoad:(UIWebView*)theWebView
 {
     if (self.callbackId != nil) {
+        // TODO: It would be more useful to return the URL the page is actually on (e.g. if it's been redirected).
+        NSString* url = [[self.inAppBrowserViewController requestedURL] absoluteString];
         CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
-                                                      messageAsDictionary:@{@"type":@"loadstop", @"url":[url absoluteString]}];
+                                                      messageAsDictionary:@{@"type":@"loadstop", @"url":url}];
         [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
 
         [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
     }
 }
 
-- (void)browserLoadError:(NSError*)error forUrl:(NSURL*)url
+- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error
 {
     if (self.callbackId != nil) {
+        NSString* url = [[self.inAppBrowserViewController requestedURL] absoluteString];
         CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR
-                                                      messageAsDictionary:@{@"type":@"loaderror", @"url":[url absoluteString], @"code": [NSNumber numberWithInt:error.code], @"message": error.localizedDescription}];
+                                                      messageAsDictionary:@{@"type":@"loaderror", @"url":url, @"code": [NSNumber numberWithInt:error.code], @"message": error.localizedDescription}];
         [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
 
         [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
@@ -214,6 +341,8 @@
 
 @implementation CDVInAppBrowserViewController
 
+@synthesize requestedURL = _requestedURL;
+
 - (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent
 {
     self = [super init];
@@ -431,18 +560,13 @@
     self.forwardButton.enabled = theWebView.canGoForward;
 
     [self.spinner startAnimating];
+
+    return [self.navigationDelegate webViewDidStartLoad:theWebView];
 }
 
-- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
+- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
 {
-    if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadStart:)]) {
-        NSURL* url = request.URL;
-        if (url == nil) {
-            url = _requestedURL;
-        }
-        [self.navigationDelegate browserLoadStart:url];
-    }
-    return YES;
+    return [self.navigationDelegate webView:theWebView shouldStartLoadWithRequest:request navigationType:navigationType];
 }
 
 - (void)webViewDidFinishLoad:(UIWebView*)theWebView
@@ -471,10 +595,7 @@
         [CDVUserAgentUtil setUserAgent:_prevUserAgent lockToken:_userAgentLockToken];
     }
 
-    if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadStop:)]) {
-        NSURL* url = theWebView.request.URL;
-        [self.navigationDelegate browserLoadStop:url];
-    }
+    [self.navigationDelegate webViewDidFinishLoad:theWebView];
 }
 
 - (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error
@@ -488,10 +609,7 @@
 
     self.addressLabel.text = @"Load Error";
 
-    if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadError:forUrl:)]) {
-        NSURL* url = theWebView.request.URL;
-        [self.navigationDelegate browserLoadError:error forUrl:url];
-    }
+    [self.navigationDelegate webView:theWebView didFailLoadWithError:error];
 }
 
 #pragma mark CDVScreenOrientationDelegate


[20/43] 2.6.0rc1 used for libs now. Bumped npm version to 2.6.0. added androids local.properties to gitignore.

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h b/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h
index f5b50eb..6e25a27 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h
@@ -23,10 +23,10 @@
 #import "NSMutableArray+QueueAdditions.h"
 #import "CDVCommandDelegate.h"
 
-#define CDVPageDidLoadNotification @"CDVPageDidLoadNotification"
-#define CDVPluginHandleOpenURLNotification @"CDVPluginHandleOpenURLNotification"
-#define CDVPluginResetNotification @"CDVPluginResetNotification"
-#define CDVLocalNotification @"CDVLocalNotification"
+NSString* const CDVPageDidLoadNotification;
+NSString* const CDVPluginHandleOpenURLNotification;
+NSString* const CDVPluginResetNotification;
+NSString* const CDVLocalNotification;
 
 @interface CDVPlugin : NSObject {}
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.m b/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.m
index a42d241..8c932a0 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.m
@@ -19,6 +19,11 @@
 
 #import "CDVPlugin.h"
 
+NSString* const CDVPageDidLoadNotification = @"CDVPageDidLoadNotification";
+NSString* const CDVPluginHandleOpenURLNotification = @"CDVPluginHandleOpenURLNotification";
+NSString* const CDVPluginResetNotification = @"CDVPluginResetNotification";
+NSString* const CDVLocalNotification = @"CDVLocalNotification";
+
 @interface CDVPlugin ()
 
 @property (readwrite, assign) BOOL hasPendingOperation;
@@ -41,7 +46,7 @@
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppTerminate) name:UIApplicationWillTerminateNotification object:nil];
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleOpenURL:) name:CDVPluginHandleOpenURLNotification object:nil];
-        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onReset) name:CDVPluginResetNotification object:nil];
+        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onReset) name:CDVPluginResetNotification object:theWebView];
 
         self.webView = theWebView;
     }
@@ -64,7 +69,7 @@
     // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveLocalNotification:) name:CDVLocalNotification object:nil];
 
     // Added in 2.5.0
-    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad:) name:CDVPageDidLoadNotification object:nil];
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad:) name:CDVPageDidLoadNotification object:self.webView];
 }
 
 - (void)dispose

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.h b/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.h
index 8683205..11b5377 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.h
@@ -37,6 +37,9 @@ typedef enum {
 @property (nonatomic, strong, readonly) NSNumber* status;
 @property (nonatomic, strong, readonly) id message;
 @property (nonatomic, strong)           NSNumber* keepCallback;
+// This property can be used to scope the lifetime of another object. For example,
+// Use it to store the associated NSData when `message` is created using initWithBytesNoCopy.
+@property (nonatomic, strong) id associatedObject;
 
 - (CDVPluginResult*)init;
 + (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal;
@@ -47,6 +50,7 @@ typedef enum {
 + (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsBool:(BOOL)theMessage;
 + (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsDictionary:(NSDictionary*)theMessage;
 + (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArrayBuffer:(NSData*)theMessage;
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsMultipart:(NSArray*)theMessages;
 + (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageToErrorObject:(int)errorCode;
 
 + (void)setVerbose:(BOOL)verbose;
@@ -54,6 +58,9 @@ typedef enum {
 
 - (void)setKeepCallbackAsBool:(BOOL)bKeepCallback;
 
+- (NSString*)argumentsAsJSON;
+
+// These methods are used by the legacy plugin return result method
 - (NSString*)toJSONString;
 - (NSString*)toSuccessCallbackString:(NSString*)callbackId;
 - (NSString*)toErrorCallbackString:(NSString*)callbackId;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.m b/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.m
index d9ba08f..af7c528 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVPluginResult.m
@@ -29,10 +29,40 @@
 @end
 
 @implementation CDVPluginResult
-@synthesize status, message, keepCallback;
+@synthesize status, message, keepCallback, associatedObject;
 
 static NSArray* org_apache_cordova_CommandStatusMsgs;
 
+id messageFromArrayBuffer(NSData* data)
+{
+    return @{
+               @"CDVType" : @"ArrayBuffer",
+               @"data" :[data base64EncodedString]
+    };
+}
+
+id massageMessage(id message)
+{
+    if ([message isKindOfClass:[NSData class]]) {
+        return messageFromArrayBuffer(message);
+    }
+    return message;
+}
+
+id messageFromMultipart(NSArray* theMessages)
+{
+    NSMutableArray* messages = [NSMutableArray arrayWithArray:theMessages];
+
+    for (NSUInteger i = 0; i < messages.count; ++i) {
+        [messages replaceObjectAtIndex:i withObject:massageMessage([messages objectAtIndex:i])];
+    }
+
+    return @{
+               @"CDVType" : @"MultiPart",
+               @"messages" : messages
+    };
+}
+
 + (void)initialize
 {
     org_apache_cordova_CommandStatusMsgs = [[NSArray alloc] initWithObjects:@"No result",
@@ -101,17 +131,17 @@ static NSArray* org_apache_cordova_CommandStatusMsgs;
 
 + (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsArrayBuffer:(NSData*)theMessage
 {
-    NSDictionary* arrDict = [NSDictionary dictionaryWithObjectsAndKeys:
-        @"ArrayBuffer", @"CDVType",
-        [theMessage base64EncodedString], @"data",
-        nil];
+    return [[self alloc] initWithStatus:statusOrdinal message:messageFromArrayBuffer(theMessage)];
+}
 
-    return [[self alloc] initWithStatus:statusOrdinal message:arrDict];
++ (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageAsMultipart:(NSArray*)theMessages
+{
+    return [[self alloc] initWithStatus:statusOrdinal message:messageFromMultipart(theMessages)];
 }
 
 + (CDVPluginResult*)resultWithStatus:(CDVCommandStatus)statusOrdinal messageToErrorObject:(int)errorCode
 {
-    NSDictionary* errDict = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:errorCode] forKey:@"code"];
+    NSDictionary* errDict = @{@"code" :[NSNumber numberWithInt:errorCode]};
 
     return [[self alloc] initWithStatus:statusOrdinal message:errDict];
 }
@@ -121,6 +151,19 @@ static NSArray* org_apache_cordova_CommandStatusMsgs;
     [self setKeepCallback:[NSNumber numberWithBool:bKeepCallback]];
 }
 
+- (NSString*)argumentsAsJSON
+{
+    id arguments = (self.message == nil ? [NSNull null] : self.message);
+    NSArray* argumentsWrappedInArray = [NSArray arrayWithObject:arguments];
+
+    NSString* argumentsJSON = [argumentsWrappedInArray JSONString];
+
+    argumentsJSON = [argumentsJSON substringWithRange:NSMakeRange(1, [argumentsJSON length] - 2)];
+
+    return argumentsJSON;
+}
+
+// These methods are used by the legacy plugin return result method
 - (NSString*)toJSONString
 {
     NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVReachability.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVReachability.m b/lib/cordova-ios/CordovaLib/Classes/CDVReachability.m
index 3c5a48b..89f4ec9 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVReachability.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVReachability.m
@@ -61,18 +61,18 @@ static void CDVPrintReachabilityFlags(SCNetworkReachabilityFlags flags, const ch
 {
 #if kShouldPrintReachabilityFlags
         NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
-        (flags & kSCNetworkReachabilityFlagsIsWWAN)               ? 'W' : '-',
-        (flags & kSCNetworkReachabilityFlagsReachable)            ? 'R' : '-',
-
-        (flags & kSCNetworkReachabilityFlagsTransientConnection)  ? 't' : '-',
-        (flags & kSCNetworkReachabilityFlagsConnectionRequired)   ? 'c' : '-',
-        (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic)  ? 'C' : '-',
-        (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
-        (flags & kSCNetworkReachabilityFlagsConnectionOnDemand)   ? 'D' : '-',
-        (flags & kSCNetworkReachabilityFlagsIsLocalAddress)       ? 'l' : '-',
-        (flags & kSCNetworkReachabilityFlagsIsDirect)             ? 'd' : '-',
-        comment
-        );
+            (flags & kSCNetworkReachabilityFlagsIsWWAN)               ? 'W' : '-',
+            (flags & kSCNetworkReachabilityFlagsReachable)            ? 'R' : '-',
+
+            (flags & kSCNetworkReachabilityFlagsTransientConnection)  ? 't' : '-',
+            (flags & kSCNetworkReachabilityFlagsConnectionRequired)   ? 'c' : '-',
+            (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic)  ? 'C' : '-',
+            (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
+            (flags & kSCNetworkReachabilityFlagsConnectionOnDemand)   ? 'D' : '-',
+            (flags & kSCNetworkReachabilityFlagsIsLocalAddress)       ? 'l' : '-',
+            (flags & kSCNetworkReachabilityFlagsIsDirect)             ? 'd' : '-',
+            comment
+            );
 #endif
 }
 
@@ -90,7 +90,7 @@ static void CDVReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRe
         return;
     }
 
-    if (![(__bridge NSObject*) info isKindOfClass:[CDVReachability class]]) {
+    if (![(__bridge NSObject*)info isKindOfClass :[CDVReachability class]]) {
         NSLog(@"info was wrong class in ReachabilityCallback");
         return;
     }
@@ -214,7 +214,7 @@ static void CDVReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkRe
     }
 
     if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand) != 0) ||
-            ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))) {
+        ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))) {
         // ... and the connection is on-demand (or on-traffic) if the
         //     calling application is using the CFSocketStream or higher APIs
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVSound.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVSound.m b/lib/cordova-ios/CordovaLib/Classes/CDVSound.m
index 99515d7..88fbbd6 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVSound.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVSound.m
@@ -87,7 +87,7 @@
         NSLog(@"Will use resource '%@' from the documents folder with path = %@", resourcePath, filePath);
     } else {
         // if resourcePath is not from FileSystem put in tmp dir, else attempt to use provided resource path
-        NSString* tmpPath = [NSTemporaryDirectory ()stringByStandardizingPath];
+        NSString* tmpPath = [NSTemporaryDirectory()stringByStandardizingPath];
         BOOL isTmp = [resourcePath rangeOfString:tmpPath].location != NSNotFound;
         BOOL isDoc = [resourcePath rangeOfString:docsPath].location != NSNotFound;
         if (!isTmp && !isDoc) {
@@ -127,7 +127,7 @@
         filePath = [self.commandDelegate pathForResource:resourcePath];
         if (filePath == nil) {
             // see if this exists in the documents/temp directory from a previous recording
-            NSString* testPath = [NSString stringWithFormat:@"%@/%@", [NSTemporaryDirectory ()stringByStandardizingPath], resourcePath];
+            NSString* testPath = [NSString stringWithFormat:@"%@/%@", [NSTemporaryDirectory()stringByStandardizingPath], resourcePath];
             if ([[NSFileManager defaultManager] fileExistsAtPath:testPath]) {
                 // inefficient as existence will be checked again below but only way to determine if file exists from previous recording
                 filePath = testPath;
@@ -385,7 +385,7 @@
             // bug in AVAudioPlayer when playing downloaded data in NSData - we have to download the file and play from disk
             CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
             CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
-            NSString* filePath = [NSString stringWithFormat:@"%@/%@", [NSTemporaryDirectory ()stringByStandardizingPath], uuidString];
+            NSString* filePath = [NSString stringWithFormat:@"%@/%@", [NSTemporaryDirectory()stringByStandardizingPath], uuidString];
             CFRelease(uuidString);
             CFRelease(uuidRef);
 
@@ -458,9 +458,19 @@
     double position = [[command.arguments objectAtIndex:1] doubleValue];
 
     if ((audioFile != nil) && (audioFile.player != nil)) {
+        NSString* jsString;
         double posInSeconds = position / 1000;
-        audioFile.player.currentTime = posInSeconds;
-        NSString* jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%f);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_POSITION, posInSeconds];
+        if (posInSeconds >= audioFile.player.duration) {
+            // The seek is past the end of file.  Stop media and reset to beginning instead of seeking past the end.
+            [audioFile.player stop];
+            audioFile.player.currentTime = 0;
+            jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%.3f);\n%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_POSITION, 0.0, @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_STOPPED];
+            // NSLog(@"seekToEndJsString=%@",jsString);
+        } else {
+            audioFile.player.currentTime = posInSeconds;
+            jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%f);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_POSITION, posInSeconds];
+            // NSLog(@"seekJsString=%@",jsString);
+        }
 
         [self.commandDelegate evalJs:jsString];
     }
@@ -625,6 +635,7 @@
         NSLog(@"Finished playing audio sample '%@'", audioFile.resourcePath);
     }
     if (flag) {
+        audioFile.player.currentTime = 0;
         jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_STATE, MEDIA_STOPPED];
     } else {
         // jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, MEDIA_ERR_DECODE];

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.h b/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.h
index a0868a0..704ab43 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.h
@@ -23,7 +23,8 @@
 @interface CDVSplashScreen : CDVPlugin {
     UIActivityIndicatorView* _activityView;
     UIImageView* _imageView;
-    UIView* _parentView;
+    NSString* _curImageName;
+    BOOL _visible;
 }
 
 - (void)show:(CDVInvokedUrlCommand*)command;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m b/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m
index cba1b53..efe3eaa 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m
@@ -19,29 +19,25 @@
 
 #import "CDVSplashScreen.h"
 
-#define kSplashScreenStateShow 0
-#define kSplashScreenStateHide 1
-
 #define kSplashScreenDurationDefault 0.25f
 
 @implementation CDVSplashScreen
 
 - (void)pluginInitialize
 {
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad) name:CDVPageDidLoadNotification object:nil];
-    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationWillChange:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad) name:CDVPageDidLoadNotification object:self.webView];
 
-    [self show:nil];
+    [self setVisible:YES];
 }
 
 - (void)show:(CDVInvokedUrlCommand*)command
 {
-    [self updateSplashScreenWithState:kSplashScreenStateShow];
+    [self setVisible:YES];
 }
 
 - (void)hide:(CDVInvokedUrlCommand*)command
 {
-    [self updateSplashScreenWithState:kSplashScreenStateHide];
+    [self setVisible:NO];
 }
 
 - (void)pageDidLoad
@@ -50,16 +46,13 @@
 
     // if value is missing, default to yes
     if ((autoHideSplashScreenValue == nil) || [autoHideSplashScreenValue boolValue]) {
-        [self hide:nil];
+        [self setVisible:NO];
     }
 }
 
-- (void)onOrientationWillChange:(NSNotification*)notification
+- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
 {
-    if (_imageView != nil) {
-        UIInterfaceOrientation orientation = [notification.userInfo[UIApplicationStatusBarOrientationUserInfoKey] intValue];
-        [self updateSplashImageForOrientation:orientation];
-    }
+    [self updateImage];
 }
 
 - (void)createViews
@@ -83,43 +76,115 @@
         topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray;
     }
 
+    UIView* parentView = self.viewController.view;
+    parentView.userInteractionEnabled = NO;  // disable user interaction while splashscreen is shown
     _activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:topActivityIndicatorStyle];
-    _activityView.tag = 2;
-    _activityView.center = self.viewController.view.center;
+    _activityView.center = CGPointMake(parentView.bounds.size.width / 2, parentView.bounds.size.height / 2);
+    _activityView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin
+        | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin;
     [_activityView startAnimating];
 
+    // Set the frame & image later.
     _imageView = [[UIImageView alloc] init];
-    [self.viewController.view addSubview:_imageView];
-    [self.viewController.view.superview addSubview:_activityView];
-    [self.viewController.view.superview layoutSubviews];
+    [parentView addSubview:_imageView];
+    [parentView addSubview:_activityView];
+
+    // Frame is required when launching in portrait mode.
+    // Bounds for landscape since it captures the rotation.
+    [parentView addObserver:self forKeyPath:@"frame" options:0 context:nil];
+    [parentView addObserver:self forKeyPath:@"bounds" options:0 context:nil];
+
+    [self updateImage];
 }
 
-- (void)updateSplashImageForOrientation:(UIInterfaceOrientation)orientation
+- (void)destroyViews
 {
-    // IPHONE (default)
-    NSString* imageName = @"Default";
+    [_imageView removeFromSuperview];
+    [_activityView removeFromSuperview];
+    _imageView = nil;
+    _activityView = nil;
+    _curImageName = nil;
+
+    self.viewController.view.userInteractionEnabled = YES;  // re-enable user interaction upon completion
+    [self.viewController.view removeObserver:self forKeyPath:@"frame"];
+    [self.viewController.view removeObserver:self forKeyPath:@"bounds"];
+}
+
+// Sets the view's frame and image.
+- (void)updateImage
+{
+    UIInterfaceOrientation orientation = self.viewController.interfaceOrientation;
+
+    // Use UILaunchImageFile if specified in plist.  Otherwise, use Default.
+    NSString* imageName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchImageFile"];
+
+    if (imageName) {
+        imageName = [imageName stringByDeletingPathExtension];
+    } else {
+        imageName = @"Default";
+    }
 
     if (CDV_IsIPhone5()) {
         imageName = [imageName stringByAppendingString:@"-568h"];
     } else if (CDV_IsIPad()) {
-        // set default to portrait upside down
-        imageName = @"Default-Portrait"; // @"Default-PortraitUpsideDown.png";
+        switch (orientation) {
+            case UIInterfaceOrientationLandscapeLeft:
+            case UIInterfaceOrientationLandscapeRight:
+                imageName = [imageName stringByAppendingString:@"-Landscape"];
+                break;
+
+            case UIInterfaceOrientationPortrait:
+            case UIInterfaceOrientationPortraitUpsideDown:
+            default:
+                imageName = [imageName stringByAppendingString:@"-Portrait"];
+                break;
+        }
+    }
+
+    if (![imageName isEqualToString:_curImageName]) {
+        UIImage* img = [UIImage imageNamed:imageName];
+        _imageView.image = img;
+        _curImageName = imageName;
+    }
+
+    [self updateBounds];
+}
 
-        if (orientation == UIInterfaceOrientationLandscapeLeft) {
-            imageName = @"Default-Landscape.png"; // @"Default-LandscapeLeft.png";
-        } else if (orientation == UIInterfaceOrientationLandscapeRight) {
-            imageName = @"Default-Landscape.png"; // @"Default-LandscapeRight.png";
+- (void)updateBounds
+{
+    UIImage* img = _imageView.image;
+    CGRect imgBounds = CGRectMake(0, 0, img.size.width, img.size.height);
+
+    CGSize screenSize = [self.viewController.view convertRect:[UIScreen mainScreen].bounds fromView:nil].size;
+
+    // There's a special case when the image is the size of the screen.
+    if (CGSizeEqualToSize(screenSize, imgBounds.size)) {
+        CGRect statusFrame = [self.viewController.view convertRect:[UIApplication sharedApplication].statusBarFrame fromView:nil];
+        imgBounds.origin.y -= statusFrame.size.height;
+    } else {
+        CGRect viewBounds = self.viewController.view.bounds;
+        CGFloat imgAspect = imgBounds.size.width / imgBounds.size.height;
+        CGFloat viewAspect = viewBounds.size.width / viewBounds.size.height;
+        // This matches the behaviour of the native splash screen.
+        CGFloat ratio;
+        if (viewAspect > imgAspect) {
+            ratio = viewBounds.size.width / imgBounds.size.width;
+        } else {
+            ratio = viewBounds.size.height / imgBounds.size.height;
         }
+        imgBounds.size.height *= ratio;
+        imgBounds.size.width *= ratio;
     }
 
-    _imageView.image = [UIImage imageNamed:imageName];
-    _imageView.frame = CGRectMake(0, 0, _imageView.image.size.width, _imageView.image.size.height);
+    _imageView.frame = imgBounds;
 }
 
-- (void)updateSplashScreenWithState:(int)state
+- (void)setVisible:(BOOL)visible
 {
-    float toAlpha = state == kSplashScreenStateShow ? 1.0f : 0.0f;
-    BOOL hidden = state == kSplashScreenStateShow ? NO : YES;
+    if (visible == _visible) {
+        return;
+    }
+    _visible = visible;
 
     id fadeSplashScreenValue = [self.commandDelegate.settings objectForKey:@"FadeSplashScreen"];
     id fadeSplashScreenDuration = [self.commandDelegate.settings objectForKey:@"FadeSplashScreenDuration"];
@@ -129,45 +194,26 @@
     if ((fadeSplashScreenValue == nil) || ![fadeSplashScreenValue boolValue]) {
         fadeDuration = 0;
     }
-    if (hidden && (_imageView == nil)) {
-        return;
-    } else if (_imageView == nil) {
-        [self createViews];
-        fadeDuration = 0;
-    }
-
-    if (!hidden) {
-        [self updateSplashImageForOrientation:self.viewController.interfaceOrientation];
-    }
 
-    if (fadeDuration == 0) {
-        [_imageView setHidden:hidden];
-        [_activityView setHidden:hidden];
-    } else {
-        if (state == kSplashScreenStateShow) {
-            // reset states
-            [_imageView setHidden:NO];
-            [_activityView setHidden:NO];
-            [_imageView setAlpha:0.0f];
-            [_activityView setAlpha:0.0f];
+    // Never animate the showing of the splash screen.
+    if (visible) {
+        if (_imageView == nil) {
+            [self createViews];
         }
-
+    } else if (fadeDuration == 0) {
+        [self destroyViews];
+    } else {
         [UIView transitionWithView:self.viewController.view
                           duration:fadeDuration
                            options:UIViewAnimationOptionTransitionNone
                         animations:^(void) {
-                [_imageView setAlpha:toAlpha];
-                [_activityView setAlpha:toAlpha];
-            }
+            [_imageView setAlpha:0];
+            [_activityView setAlpha:0];
+        }
+
                         completion:^(BOOL finished) {
-                if (state == kSplashScreenStateHide) {
-                    // Clean-up resources.
-                    [_imageView removeFromSuperview];
-                    [_activityView removeFromSuperview];
-                    _imageView = nil;
-                    _activityView = nil;
-                }
-            }];
+            [self destroyViews];
+        }];
     }
 }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.m b/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.m
index 1959c77..afc10de 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.m
@@ -31,7 +31,7 @@
 @property (nonatomic) NSInteger statusCode;
 @end
 
-static CDVWhitelist * gWhitelist = nil;
+static CDVWhitelist* gWhitelist = nil;
 // Contains a set of NSNumbers of addresses of controllers. It doesn't store
 // the actual pointer to avoid retaining.
 static NSMutableSet* gRegisteredControllers = nil;
@@ -159,12 +159,12 @@ static CDVViewController *viewControllerForRequest(NSURLRequest* request)
         [self sendResponseWithResponseCode:200 data:nil mimeType:nil];
         return;
     } else if ([[url absoluteString] hasPrefix:kCDVAssetsLibraryPrefix]) {
-        ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset * asset) {
+        ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
             if (asset) {
                 // We have the asset!  Get the data and send it along.
                 ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
-                NSString* MIMEType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass ((__bridge CFStringRef)[assetRepresentation UTI], kUTTagClassMIMEType);
-                Byte* buffer = (Byte*)malloc ([assetRepresentation size]);
+                NSString* MIMEType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)[assetRepresentation UTI], kUTTagClassMIMEType);
+                Byte* buffer = (Byte*)malloc([assetRepresentation size]);
                 NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil];
                 NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
                 [self sendResponseWithResponseCode:200 data:data mimeType:MIMEType];
@@ -173,7 +173,7 @@ static CDVViewController *viewControllerForRequest(NSURLRequest* request)
                 [self sendResponseWithResponseCode:404 data:nil mimeType:nil];
             }
         };
-        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) {
+        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
             // Retrieving the asset failed for some reason.  Send an error.
             [self sendResponseWithResponseCode:401 data:nil mimeType:nil];
         };
@@ -202,7 +202,7 @@ static CDVViewController *viewControllerForRequest(NSURLRequest* request)
     if (mimeType == nil) {
         mimeType = @"text/plain";
     }
-    NSString* encodingName = [@"text/plain" isEqualToString:mimeType] ? @"UTF-8" : nil;
+    NSString* encodingName = [@"text/plain" isEqualToString : mimeType] ? @"UTF-8" : nil;
     CDVHTTPURLResponse* response =
         [[CDVHTTPURLResponse alloc] initWithURL:[[self request] URL]
                                        MIMEType:mimeType

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.m b/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.m
index 5c43c51..9923d47 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.m
@@ -96,7 +96,7 @@ static NSMutableArray* gPendingSetUserAgentBlocks = nil;
         void (^block)() = [gPendingSetUserAgentBlocks objectAtIndex:0];
         [gPendingSetUserAgentBlocks removeObjectAtIndex:0];
         gCurrentLockToken = ++gNextLockToken;
-        NSLog (@"Gave lock %d", gCurrentLockToken);
+        NSLog(@"Gave lock %d", gCurrentLockToken);
         block(gCurrentLockToken);
     } else {
         gCurrentLockToken = 0;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVViewController.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVViewController.h b/lib/cordova-ios/CordovaLib/Classes/CDVViewController.h
index 82e22f6..2338baf 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVViewController.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVViewController.h
@@ -22,15 +22,14 @@
 #import "CDVAvailability.h"
 #import "CDVInvokedUrlCommand.h"
 #import "CDVCommandDelegate.h"
+#import "CDVCommandQueue.h"
 #import "CDVWhitelist.h"
 #import "CDVScreenOrientationDelegate.h"
-
-@class CDVCommandQueue;
-@class CDVCommandDelegateImpl;
+#import "CDVPlugin.h"
 
 @interface CDVViewController : UIViewController <UIWebViewDelegate, CDVScreenOrientationDelegate>{
     @protected
-    CDVCommandDelegateImpl* _commandDelegate;
+    id <CDVCommandDelegate> _commandDelegate;
     @protected
     CDVCommandQueue* _commandQueue;
     NSString* _userAgent;
@@ -49,7 +48,7 @@
 @property (nonatomic, readwrite, copy) NSString* wwwFolderName;
 @property (nonatomic, readwrite, copy) NSString* startPage;
 @property (nonatomic, readonly, strong) CDVCommandQueue* commandQueue;
-@property (nonatomic, readonly, strong) CDVCommandDelegateImpl* commandDelegate;
+@property (nonatomic, readonly, strong) id <CDVCommandDelegate> commandDelegate;
 @property (nonatomic, readonly) NSString* userAgent;
 
 + (NSDictionary*)getBundlePlist:(NSString*)plistName;
@@ -67,6 +66,7 @@
 
 - (id)getCommandInstance:(NSString*)pluginName;
 - (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className;
+- (void)registerPlugin:(CDVPlugin*)plugin withPluginName:(NSString*)pluginName;
 
 - (BOOL)URLisAllowed:(NSURL*)url;
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m b/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m
index bec716d..c7ad01b 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m
@@ -19,7 +19,6 @@
 
 #import <objc/message.h>
 #import "CDV.h"
-#import "CDVCommandQueue.h"
 #import "CDVCommandDelegateImpl.h"
 #import "CDVConfigParser.h"
 #import "CDVUserAgentUtil.h"
@@ -103,6 +102,48 @@
     return self;
 }
 
+- (void)viewWillAppear:(BOOL)animated
+{
+    [super viewWillAppear:animated];
+
+    NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+    [nc addObserver:self
+           selector:@selector(keyboardWillShowOrHide:)
+               name:UIKeyboardWillShowNotification
+             object:nil];
+    [nc addObserver:self
+           selector:@selector(keyboardWillShowOrHide:)
+               name:UIKeyboardWillHideNotification
+             object:nil];
+}
+
+- (void)viewWillDisappear:(BOOL)animated
+{
+    [super viewWillDisappear:animated];
+
+    NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+    [nc removeObserver:self name:UIKeyboardWillShowNotification object:nil];
+    [nc removeObserver:self name:UIKeyboardWillHideNotification object:nil];
+}
+
+- (void)keyboardWillShowOrHide:(NSNotification*)notif
+{
+    if (![@"true" isEqualToString:self.settings[@"KeyboardShrinksView"]]) {
+        return;
+    }
+    BOOL showEvent = [notif.name isEqualToString:UIKeyboardWillShowNotification];
+
+    CGRect keyboardFrame = [notif.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
+    keyboardFrame = [self.view convertRect:keyboardFrame fromView:nil];
+
+    CGRect newFrame = self.view.bounds;
+    if (showEvent) {
+        newFrame.size.height -= keyboardFrame.size.height;
+    }
+    self.webView.frame = newFrame;
+    self.webView.scrollView.contentInset = UIEdgeInsetsMake(0, 0, -keyboardFrame.size.height, 0);
+}
+
 - (void)printDeprecationNotice
 {
     if (!IsAtLeastiOSVersion(@"5.0")) {
@@ -208,9 +249,6 @@
     id backupWebStorage = self.settings[@"BackupWebStorage"];
     if ([backupWebStorage isKindOfClass:[NSString class]]) {
         backupWebStorageType = backupWebStorage;
-    } else if ([backupWebStorage isKindOfClass:[NSNumber class]]) {
-        NSLog(@"Deprecated: BackupWebStorage boolean property is a string property now (none, local, cloud). A boolean value of 'true' will be mapped to 'cloud'. Consult the docs: http://docs.cordova.io/en/edge/guide_project-settings_ios_index.md.html#Project%%20Settings%%20for%%20iOS");
-        backupWebStorageType = [(NSNumber*) backupWebStorage boolValue] ? @"cloud" : @"none";
     }
     self.settings[@"BackupWebStorage"] = backupWebStorageType;
 
@@ -231,6 +269,10 @@
     if ([self.settings objectForKey:@"MediaPlaybackRequiresUserAction"]) {
         mediaPlaybackRequiresUserAction = [(NSNumber*)[settings objectForKey:@"MediaPlaybackRequiresUserAction"] boolValue];
     }
+    BOOL hideKeyboardFormAccessoryBar = NO;  // default value
+    if ([self.settings objectForKey:@"HideKeyboardFormAccessoryBar"]) {
+        hideKeyboardFormAccessoryBar = [(NSNumber*)[settings objectForKey:@"HideKeyboardFormAccessoryBar"] boolValue];
+    }
 
     self.webView.scalesPageToFit = [enableViewportScale boolValue];
 
@@ -239,15 +281,27 @@
      */
 
     if ([enableLocation boolValue]) {
+        NSLog(@"Deprecated: The 'EnableLocation' boolean property is deprecated in 2.5.0, and will be removed in 3.0.0. Use the 'onload' boolean attribute (of the CDVLocation plugin.");
         [[self.commandDelegate getCommandInstance:@"Geolocation"] getLocation:[CDVInvokedUrlCommand new]];
     }
 
+    if (hideKeyboardFormAccessoryBar) {
+        __weak CDVViewController* weakSelf = self;
+        [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillShowNotification
+                                                          object:nil
+                                                           queue:[NSOperationQueue mainQueue]
+                                                      usingBlock:^(NSNotification * notification) {
+                // we can't hide it here because the accessory bar hasn't been created yet, so we delay on the queue
+                [weakSelf performSelector:@selector(hideKeyboardFormAccessoryBar) withObject:nil afterDelay:0];
+            }];
+    }
+
     /*
      * Fire up CDVLocalStorage to work-around WebKit storage limitations: on all iOS 5.1+ versions for local-only backups, but only needed on iOS 5.1 for cloud backup.
      */
-    if (IsAtLeastiOSVersion(@"5.1") && (([backupWebStorageType isEqualToString:@"local"]) ||
-            ([backupWebStorageType isEqualToString:@"cloud"] && !IsAtLeastiOSVersion(@"6.0")))) {
-        [self registerPlugin:[[CDVLocalStorage alloc] initWithWebView:self.webView] withClassName:NSStringFromClass([CDVLocalStorage class])];
+    if (IsAtLeastiOSVersion (@"5.1") && (([backupWebStorageType isEqualToString:@"local"]) ||
+            ([backupWebStorageType isEqualToString:@"cloud"] && !IsAtLeastiOSVersion (@"6.0")))) {
+        [self registerPlugin:[[CDVLocalStorage alloc] initWithWebView:self.webView] withClassName:NSStringFromClass ([CDVLocalStorage class])];
     }
 
     /*
@@ -260,12 +314,19 @@
         self.webView.mediaPlaybackRequiresUserAction = NO;
     }
 
-    // UIWebViewBounce property - defaults to true
-    NSNumber* bouncePreference = [self.settings objectForKey:@"UIWebViewBounce"];
-    BOOL bounceAllowed = (bouncePreference == nil || [bouncePreference boolValue]);
+    // By default, overscroll bouncing is allowed.
+    // UIWebViewBounce has been renamed to DisallowOverscroll, but both are checked.
+    BOOL bounceAllowed = YES;
+    NSNumber* disallowOverscroll = [self.settings objectForKey:@"DisallowOverscroll"];
+    if (disallowOverscroll == nil) {
+        NSNumber* bouncePreference = [self.settings objectForKey:@"UIWebViewBounce"];
+        bounceAllowed = (bouncePreference == nil || [bouncePreference boolValue]);
+    } else {
+        bounceAllowed = ![disallowOverscroll boolValue];
+    }
 
     // prevent webView from bouncing
-    // based on UIWebViewBounce key in config.xml
+    // based on the DisallowOverscroll/UIWebViewBounce key in config.xml
     if (!bounceAllowed) {
         if ([self.webView respondsToSelector:@selector(scrollView)]) {
             ((UIScrollView*)[self.webView scrollView]).bounces = NO;
@@ -281,7 +342,7 @@
     /*
      * iOS 6.0 UIWebView properties
      */
-    if (IsAtLeastiOSVersion(@"6.0")) {
+    if (IsAtLeastiOSVersion (@"6.0")) {
         BOOL keyboardDisplayRequiresUserAction = YES; // KeyboardDisplayRequiresUserAction - defaults to YES
         if ([self.settings objectForKey:@"KeyboardDisplayRequiresUserAction"] != nil) {
             if ([self.settings objectForKey:@"KeyboardDisplayRequiresUserAction"]) {
@@ -330,6 +391,34 @@
         }];
 }
 
+- (void)hideKeyboardFormAccessoryBar
+{
+    NSArray* windows = [[UIApplication sharedApplication] windows];
+
+    for (UIWindow* window in windows) {
+        for (UIView* view in window.subviews) {
+            if ([[view description] hasPrefix:@"<UIPeripheralHostView"]) {
+                for (UIView* peripheralView in view.subviews) {
+                    // hides the accessory bar
+                    if ([[peripheralView description] hasPrefix:@"<UIWebFormAccessory"]) {
+                        // remove the extra scroll space for the form accessory bar
+                        CGRect newFrame = self.webView.scrollView.frame;
+                        newFrame.size.height += peripheralView.frame.size.height;
+                        self.webView.scrollView.frame = newFrame;
+
+                        // remove the form accessory bar
+                        [peripheralView removeFromSuperview];
+                    }
+                    // hides the thin grey line used to adorn the bar (iOS 6)
+                    if ([[peripheralView description] hasPrefix:@"<UIImageView"]) {
+                        [[peripheralView layer] setOpacity:0.0];
+                    }
+                }
+            }
+        }
+    }
+}
+
 - (NSArray*)parseInterfaceOrientations:(NSArray*)orientations
 {
     NSMutableArray* result = [[NSMutableArray alloc] init];
@@ -531,7 +620,7 @@
 
     [self processOpenUrl];
 
-    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPageDidLoadNotification object:nil]];
+    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPageDidLoadNotification object:self.webView]];
 }
 
 - (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error
@@ -660,6 +749,22 @@
     [plugin pluginInitialize];
 }
 
+- (void)registerPlugin:(CDVPlugin*)plugin withPluginName:(NSString*)pluginName
+{
+    if ([plugin respondsToSelector:@selector(setViewController:)]) {
+        [plugin setViewController:self];
+    }
+
+    if ([plugin respondsToSelector:@selector(setCommandDelegate:)]) {
+        [plugin setCommandDelegate:_commandDelegate];
+    }
+
+    NSString* className = NSStringFromClass([plugin class]);
+    [self.pluginObjects setObject:plugin forKey:className];
+    [self.pluginsMap setValue:className forKey:[pluginName lowercaseString]];
+    [plugin pluginInitialize];
+}
+
 /**
  Returns an instance of a CordovaCommand object, based on its name.  If one exists already, it is returned.
  */
@@ -814,13 +919,8 @@
 - (void)dealloc
 {
     [CDVURLProtocol unregisterViewController:self];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillTerminateNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSCurrentLocaleDidChangeNotification object:nil];
-    [[NSNotificationCenter defaultCenter] removeObserver:self name:CDVPluginHandleOpenURLNotification object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+
     self.webView.delegate = nil;
     self.webView = nil;
     [CDVUserAgentUtil releaseLock:&_userAgentLockToken];

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m b/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m
index 9ee8186..a72bfb9 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m
@@ -68,7 +68,9 @@ typedef enum {
     if (![self isJsLoadTokenSet:webView]) {
         _state = STATE_WAITING_FOR_FINISH;
         [self setLoadToken:webView];
-        [_delegate webViewDidStartLoad:webView];
+        if ([_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
+            [_delegate webViewDidStartLoad:webView];
+        }
         [self pollForPageLoadFinish:webView];
     }
 }
@@ -80,7 +82,9 @@ typedef enum {
     }
     if ([self isPageLoaded:webView]) {
         _state = STATE_SHOULD_LOAD_MISSING;
-        [_delegate webViewDidFinishLoad:webView];
+        if ([_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
+            [_delegate webViewDidFinishLoad:webView];
+        }
     } else {
         [self performSelector:@selector(pollForPageLoaded) withObject:webView afterDelay:50];
     }
@@ -88,7 +92,11 @@ typedef enum {
 
 - (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
 {
-    BOOL shouldLoad = [_delegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
+    BOOL shouldLoad = YES;
+
+    if ([_delegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) {
+        shouldLoad = [_delegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
+    }
 
     if (shouldLoad) {
         BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]];
@@ -104,7 +112,9 @@ typedef enum {
 {
     if (_state == STATE_NORMAL) {
         if (_loadCount == 0) {
-            [_delegate webViewDidStartLoad:webView];
+            if ([_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
+                [_delegate webViewDidStartLoad:webView];
+            }
             _loadCount += 1;
         } else if (_loadCount > 0) {
             _loadCount += 1;
@@ -128,8 +138,10 @@ typedef enum {
 {
     if (_state == STATE_NORMAL) {
         if (_loadCount == 1) {
-            [_delegate webViewDidFinishLoad:webView];
-            _loadCount -= 1;
+            if ([_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
+                [_delegate webViewDidFinishLoad:webView];
+            }
+            _loadCount = -1;
         } else if (_loadCount > 1) {
             _loadCount -= 1;
         }
@@ -143,8 +155,10 @@ typedef enum {
 {
     if (_state == STATE_NORMAL) {
         if (_loadCount == 1) {
-            [_delegate webView:webView didFailLoadWithError:error];
-            _loadCount -= 1;
+            if ([_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
+                [_delegate webView:webView didFailLoadWithError:error];
+            }
+            _loadCount = -1;
         } else if (_loadCount > 1) {
             _loadCount -= 1;
         }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/NSData+Base64.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/NSData+Base64.m b/lib/cordova-ios/CordovaLib/Classes/NSData+Base64.m
index 08c801b..d0f2189 100644
--- a/lib/cordova-ios/CordovaLib/Classes/NSData+Base64.m
+++ b/lib/cordova-ios/CordovaLib/Classes/NSData+Base64.m
@@ -249,13 +249,10 @@ char *CDVNewBase64Encode(
 //
 + (NSData*)dataFromBase64String:(NSString*)aString
 {
-    NSData* data = [aString dataUsingEncoding:NSASCIIStringEncoding];
-    size_t outputLength;
-    void* outputBuffer = CDVNewBase64Decode([data bytes], [data length], &outputLength);
-    NSData* result = [NSData dataWithBytes:outputBuffer length:outputLength];
+    size_t outputLength = 0;
+    void* outputBuffer = CDVNewBase64Decode([aString UTF8String], [aString length], &outputLength);
 
-    free(outputBuffer);
-    return result;
+    return [NSData dataWithBytesNoCopy:outputBuffer length:outputLength freeWhenDone:YES];
 }
 
 //
@@ -273,13 +270,11 @@ char *CDVNewBase64Encode(
     char* outputBuffer =
         CDVNewBase64Encode([self bytes], [self length], true, &outputLength);
 
-    NSString* result =
-        [[NSString alloc]
-        initWithBytes:outputBuffer
-               length:outputLength
-             encoding:NSASCIIStringEncoding];
+    NSString* result = [[NSString alloc] initWithBytesNoCopy:outputBuffer
+                                                      length:outputLength
+                                                    encoding:NSASCIIStringEncoding
+                                                freeWhenDone:YES];
 
-    free(outputBuffer);
     return result;
 }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/NSDictionary+Extensions.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/NSDictionary+Extensions.m b/lib/cordova-ios/CordovaLib/Classes/NSDictionary+Extensions.m
index 80e9ac1..0361ff9 100644
--- a/lib/cordova-ios/CordovaLib/Classes/NSDictionary+Extensions.m
+++ b/lib/cordova-ios/CordovaLib/Classes/NSDictionary+Extensions.m
@@ -28,7 +28,7 @@
     bool exists = false;
 
     if (val != nil) {
-        exists = [(NSString*) val compare:expectedValue options:NSCaseInsensitiveSearch] == 0;
+        exists = [(NSString*)val compare : expectedValue options : NSCaseInsensitiveSearch] == 0;
     }
 
     return exists;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj b/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
index 4868020..e14f1f6 100644
--- a/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
+++ b/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
@@ -44,6 +44,9 @@
 		30F5EBAB14CA26E700987760 /* CDVCommandDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 30F5EBA914CA26E700987760 /* CDVCommandDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		3E76876D156A90EE00EB6FA3 /* CDVLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E76876B156A90EE00EB6FA3 /* CDVLogger.m */; };
 		3E76876F156A90EE00EB6FA3 /* CDVLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 3E76876C156A90EE00EB6FA3 /* CDVLogger.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		68B7516E16FD18190076A8B4 /* CDVJpegHeaderWriter.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B7516B16FD18190076A8B4 /* CDVJpegHeaderWriter.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		68B7516F16FD18190076A8B4 /* CDVJpegHeaderWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 68B7516C16FD18190076A8B4 /* CDVJpegHeaderWriter.m */; };
+		68B7517016FD19F80076A8B4 /* CDVExif.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B7516A16FD18190076A8B4 /* CDVExif.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		8852C43A14B65FD800F0E735 /* CDVViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8852C43614B65FD800F0E735 /* CDVViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		8852C43C14B65FD800F0E735 /* CDVViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8852C43714B65FD800F0E735 /* CDVViewController.m */; };
 		8887FD661090FBE7009987E8 /* CDVCamera.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD261090FBE7009987E8 /* CDVCamera.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -141,6 +144,10 @@
 		686357DC14100B1600DF4CF2 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
 		68A32D7114102E1C006B237C /* libCordova.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCordova.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		68A32D7414103017006B237C /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; };
+		68B7516A16FD18190076A8B4 /* CDVExif.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVExif.h; path = Classes/CDVExif.h; sourceTree = "<group>"; };
+		68B7516B16FD18190076A8B4 /* CDVJpegHeaderWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVJpegHeaderWriter.h; path = Classes/CDVJpegHeaderWriter.h; sourceTree = "<group>"; };
+		68B7516C16FD18190076A8B4 /* CDVJpegHeaderWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVJpegHeaderWriter.m; path = Classes/CDVJpegHeaderWriter.m; sourceTree = "<group>"; };
+		8220B5C316D5427E00EC3921 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; };
 		8852C43614B65FD800F0E735 /* CDVViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVViewController.h; path = Classes/CDVViewController.h; sourceTree = "<group>"; };
 		8852C43714B65FD800F0E735 /* CDVViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVViewController.m; path = Classes/CDVViewController.m; sourceTree = "<group>"; };
 		8887FD261090FBE7009987E8 /* CDVCamera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVCamera.h; path = Classes/CDVCamera.h; sourceTree = "<group>"; };
@@ -223,6 +230,7 @@
 			isa = PBXGroup;
 			children = (
 				68A32D7414103017006B237C /* AddressBook.framework */,
+				8220B5C316D5427E00EC3921 /* AssetsLibrary.framework */,
 				686357DC14100B1600DF4CF2 /* CoreMedia.framework */,
 				686357CE14100ADA00DF4CF2 /* AudioToolbox.framework */,
 				686357CF14100ADB00DF4CF2 /* AVFoundation.framework */,
@@ -292,6 +300,9 @@
 				8887FD271090FBE7009987E8 /* CDVCamera.m */,
 				1F584B991385A28900ED25E8 /* CDVCapture.h */,
 				1F584B9A1385A28900ED25E8 /* CDVCapture.m */,
+				68B7516A16FD18190076A8B4 /* CDVExif.h */,
+				68B7516B16FD18190076A8B4 /* CDVJpegHeaderWriter.h */,
+				68B7516C16FD18190076A8B4 /* CDVJpegHeaderWriter.m */,
 				1F3C04CC12BC247D004F9E10 /* CDVContact.h */,
 				1F3C04CD12BC247D004F9E10 /* CDVContact.m */,
 				8887FD2A1090FBE7009987E8 /* CDVContacts.h */,
@@ -364,6 +375,8 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				68B7517016FD19F80076A8B4 /* CDVExif.h in Headers */,
+				68B7516E16FD18190076A8B4 /* CDVJpegHeaderWriter.h in Headers */,
 				8887FD661090FBE7009987E8 /* CDVCamera.h in Headers */,
 				8887FD681090FBE7009987E8 /* NSDictionary+Extensions.h in Headers */,
 				8887FD6A1090FBE7009987E8 /* CDVContacts.h in Headers */,
@@ -502,6 +515,7 @@
 				30F3930C169F839700B22307 /* CDVJSON.m in Sources */,
 				EB96673C16A8970A00D86CDF /* CDVUserAgentUtil.m in Sources */,
 				EBFF4DBC16D3FE2E008F452B /* CDVWebViewDelegate.m in Sources */,
+				68B7516F16FD18190076A8B4 /* CDVJpegHeaderWriter.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/VERSION b/lib/cordova-ios/CordovaLib/VERSION
index 437459c..f47de85 100644
--- a/lib/cordova-ios/CordovaLib/VERSION
+++ b/lib/cordova-ios/CordovaLib/VERSION
@@ -1 +1 @@
-2.5.0
+2.6.0rc1

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/cordova.ios.js
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/cordova.ios.js b/lib/cordova-ios/CordovaLib/cordova.ios.js
index 3d83df3..8ed1706 100644
--- a/lib/cordova-ios/CordovaLib/cordova.ios.js
+++ b/lib/cordova-ios/CordovaLib/cordova.ios.js
@@ -1,8 +1,8 @@
 // Platform: ios
 
-// commit f50d20a87431c79a54572263729461883f611a53
+// commit 47593b2bc1dba9bf46545b1da24577f937966e12
 
-// File generated at :: Tue Feb 26 2013 14:26:19 GMT-0800 (PST)
+// File generated at :: Thu Mar 21 2013 15:44:06 GMT-0700 (PDT)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -262,7 +262,7 @@ var cordova = {
      */
     callbackSuccess: function(callbackId, args) {
         try {
-            cordova.callbackFromNative(callbackId, true, args.status, args.message, args.keepCallback);
+            cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
         } catch (e) {
             console.log("Error in error callback: " + callbackId + " = "+e);
         }
@@ -275,7 +275,7 @@ var cordova = {
         // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
         // Derive success from status.
         try {
-            cordova.callbackFromNative(callbackId, false, args.status, args.message, args.keepCallback);
+            cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
         } catch (e) {
             console.log("Error in error callback: " + callbackId + " = "+e);
         }
@@ -284,13 +284,13 @@ var cordova = {
     /**
      * Called by native code when returning the result from an action.
      */
-    callbackFromNative: function(callbackId, success, status, message, keepCallback) {
+    callbackFromNative: function(callbackId, success, status, args, keepCallback) {
         var callback = cordova.callbacks[callbackId];
         if (callback) {
             if (success && status == cordova.callbackStatus.OK) {
-                callback.success && callback.success(message);
+                callback.success && callback.success.apply(null, args);
             } else if (!success) {
-                callback.fail && callback.fail(message);
+                callback.fail && callback.fail.apply(null, args);
             }
 
             // Clear callback if not expecting any more results
@@ -724,6 +724,9 @@ channel.createSticky('onCordovaInfoReady');
 // Event to indicate that the connection property has been set.
 channel.createSticky('onCordovaConnectionReady');
 
+// 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');
 
@@ -826,6 +829,7 @@ function massageArgsJsToNative(args) {
     if (!args || utils.typeName(args) != 'Array') {
        return args;
     }
+    var ret = [];
     var encodeArrayBufferAs8bitString = function(ab) {
         return String.fromCharCode.apply(null, new Uint8Array(ab));
     };
@@ -834,17 +838,19 @@ function massageArgsJsToNative(args) {
     };
     args.forEach(function(arg, i) {
         if (utils.typeName(arg) == 'ArrayBuffer') {
-            args[i] = {
+            ret.push({
                 'CDVType': 'ArrayBuffer',
                 'data': encodeArrayBufferAsBase64(arg)
-            };
+            });
+        } else {
+            ret.push(arg);
         }
     });
-    return args;
+    return ret;
 }
 
-function massagePayloadNativeToJs(payload) {
-    if (payload && payload.hasOwnProperty('CDVType') && payload.CDVType == 'ArrayBuffer') {
+function massageMessageNativeToJs(message) {
+    if (message.CDVType == 'ArrayBuffer') {
         var stringToArrayBuffer = function(str) {
             var ret = new Uint8Array(str.length);
             for (var i = 0; i < str.length; i++) {
@@ -855,9 +861,23 @@ function massagePayloadNativeToJs(payload) {
         var base64ToArrayBuffer = function(b64) {
             return stringToArrayBuffer(atob(b64));
         };
-        payload = base64ToArrayBuffer(payload.data);
+        message = base64ToArrayBuffer(message.data);
+    }
+    return message;
+}
+
+function convertMessageToArgsNativeToJs(message) {
+    var args = [];
+    if (!message || !message.hasOwnProperty('CDVType')) {
+        args.push(message);
+    } else if (message.CDVType == 'MultiPart') {
+        message.messages.forEach(function(e) {
+            args.push(massageMessageNativeToJs(e));
+        });
+    } else {
+        args.push(massageMessageNativeToJs(message));
     }
-    return payload;
+    return args;
 }
 
 function iOSExec() {
@@ -964,11 +984,11 @@ iOSExec.nativeFetchMessages = function() {
     return json;
 };
 
-iOSExec.nativeCallback = function(callbackId, status, payload, keepCallback) {
+iOSExec.nativeCallback = function(callbackId, status, message, keepCallback) {
     return iOSExec.nativeEvalAndFetch(function() {
         var success = status === 0 || status === 1;
-        payload = massagePayloadNativeToJs(payload);
-        cordova.callbackFromNative(callbackId, success, status, payload, keepCallback);
+        var args = convertMessageToArgsNativeToJs(message);
+        cordova.callbackFromNative(callbackId, success, status, args, keepCallback);
     });
 };
 
@@ -1161,9 +1181,10 @@ cameraExport.getPicture = function(successCallback, errorCallback, options) {
     var correctOrientation = !!options.correctOrientation;
     var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
     var popoverOptions = getValue(options.popoverOptions, null);
+    var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
 
     var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
-                mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions];
+                mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
 
     exec(successCallback, errorCallback, "Camera", "takePicture", args);
     return new CameraPopoverHandle();
@@ -1206,6 +1227,10 @@ module.exports = {
       ARROW_LEFT : 4,
       ARROW_RIGHT : 8,
       ARROW_ANY : 15
+  },
+  Direction:{
+      BACK: 0,
+      FRONT: 1
   }
 };
 
@@ -2398,14 +2423,7 @@ FileReader.prototype.readAsText = function(file, encoding) {
     // Default encoding is UTF-8
     var enc = encoding ? encoding : "UTF-8";
     var me = this;
-    var execArgs = [this._fileName, enc];
-
-    // Maybe add slice parameters.
-    if (file.end < file.size) {
-        execArgs.push(file.start, file.end);
-    } else if (file.start > 0) {
-        execArgs.push(file.start);
-    }
+    var execArgs = [this._fileName, enc, file.start, file.end];
 
     // Read file
     exec(
@@ -2474,14 +2492,7 @@ FileReader.prototype.readAsDataURL = function(file) {
     }
 
     var me = this;
-    var execArgs = [this._fileName];
-
-    // Maybe add slice parameters.
-    if (file.end < file.size) {
-        execArgs.push(file.start, file.end);
-    } else if (file.start > 0) {
-        execArgs.push(file.start);
-    }
+    var execArgs = [this._fileName, file.start, file.end];
 
     // Read file
     exec(
@@ -2544,9 +2555,59 @@ FileReader.prototype.readAsBinaryString = function(file) {
     if (initRead(this, file)) {
         return this._realReader.readAsBinaryString(file);
     }
-    // TODO - Can't return binary data to browser.
-    console.log('method "readAsBinaryString" is not supported at this time.');
-    this.abort();
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsBinaryString", execArgs);
 };
 
 /**
@@ -2558,9 +2619,59 @@ FileReader.prototype.readAsArrayBuffer = function(file) {
     if (initRead(this, file)) {
         return this._realReader.readAsArrayBuffer(file);
     }
-    // TODO - Can't return binary data to browser.
-    console.log('This method is not supported at this time.');
-    this.abort();
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsArrayBuffer", execArgs);
 };
 
 module.exports = FileReader;
@@ -2606,6 +2717,38 @@ function newProgressEvent(result) {
     return pe;
 }
 
+function getBasicAuthHeader(urlString) {
+    var header =  null;
+
+    if (window.btoa) {
+        // parse the url using the Location object
+        var url = document.createElement('a');
+        url.href = urlString;
+
+        var credentials = null;
+        var protocol = url.protocol + "//";
+        var origin = protocol + url.host;
+
+        // check whether there are the username:password credentials in the url
+        if (url.href.indexOf(origin) != 0) { // credentials found
+            var atIndex = url.href.indexOf("@");
+            credentials = url.href.substring(protocol.length, atIndex);
+        }
+
+        if (credentials) {
+            var authHeader = "Authorization";
+            var authHeaderValue = "Basic " + window.btoa(credentials);
+
+            header = {
+                name : authHeader,
+                value : authHeaderValue
+            };
+        }
+    }
+
+    return header;
+}
+
 var idCounter = 0;
 
 /**
@@ -2636,6 +2779,18 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
     var params = null;
     var chunkedMode = true;
     var headers = null;
+
+    var basicAuthHeader = getBasicAuthHeader(server);
+    if (basicAuthHeader) {
+        if (!options) {
+            options = new FileUploadOptions();
+        }
+        if (!options.headers) {
+            options.headers = {};
+        }
+        options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+    }
+
     if (options) {
         fileKey = options.fileKey;
         fileName = options.fileName;
@@ -2653,7 +2808,7 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
     }
 
     var fail = errorCallback && function(e) {
-        var error = new FileTransferError(e.code, e.source, e.target, e.http_status);
+        var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
         errorCallback(error);
     };
 
@@ -2677,10 +2832,28 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
  * @param successCallback (Function}  Callback to be invoked when upload has completed
  * @param errorCallback {Function}    Callback to be invoked upon error
  * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+ * @param options {FileDownloadOptions} Optional parameters such as headers
  */
-FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts) {
+FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts, options) {
     argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments);
     var self = this;
+
+    var basicAuthHeader = getBasicAuthHeader(source);
+    if (basicAuthHeader) {
+        if (!options) {
+            options = {};
+        }
+        if (!options.headers) {
+            options.headers = {};
+        }
+        options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+    }
+
+    var headers = null;
+    if (options) {
+        headers = options.headers || null;
+    }
+
     var win = function(result) {
         if (typeof result.lengthComputable != "undefined") {
             if (self.onprogress) {
@@ -2703,11 +2876,11 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
     };
 
     var fail = errorCallback && function(e) {
-        var error = new FileTransferError(e.code, e.source, e.target, e.http_status);
+        var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
         errorCallback(error);
     };
 
-    exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id]);
+    exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id, headers]);
 };
 
 /**
@@ -3105,6 +3278,7 @@ function InAppBrowser() {
    this.channels = {
         'loadstart': channel.create('loadstart'),
         'loadstop' : channel.create('loadstop'),
+        'loaderror' : channel.create('loaderror'),
         'exit' : channel.create('exit')
    };
 }
@@ -3135,7 +3309,7 @@ module.exports = function(strUrl, strWindowName, strWindowFeatures) {
     var cb = function(eventname) {
        iab._eventHandler(eventname);
     };
-    exec(cb, null, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
+    exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
     return iab;
 };
 
@@ -4341,7 +4515,8 @@ modulemapper.clobbers('cordova/plugin/device', 'device');
 // file: lib/common/plugin/echo.js
 define("cordova/plugin/echo", function(require, exports, module) {
 
-var exec = require('cordova/exec');
+var exec = require('cordova/exec'),
+    utils = require('cordova/utils');
 
 /**
  * Sends the given message through exec() to the Echo plugin, which sends it back to the successCallback.
@@ -4351,11 +4526,25 @@ var exec = require('cordova/exec');
  * @param forceAsync  Whether to force an async return value (for testing native->js bridge).
  */
 module.exports = function(successCallback, errorCallback, message, forceAsync) {
-    var action = forceAsync ? 'echoAsync' : 'echo';
-    if (!forceAsync && message.constructor == ArrayBuffer) {
-        action = 'echoArrayBuffer';
+    var action = 'echo';
+    var messageIsMultipart = (utils.typeName(message) == "Array");
+    var args = messageIsMultipart ? message : [message];
+
+    if (utils.typeName(message) == 'ArrayBuffer') {
+        if (forceAsync) {
+            console.warn('Cannot echo ArrayBuffer with forced async, falling back to sync.');
+        }
+        action += 'ArrayBuffer';
+    } else if (messageIsMultipart) {
+        if (forceAsync) {
+            console.warn('Cannot echo MultiPart Array with forced async, falling back to sync.');
+        }
+        action += 'MultiPart';
+    } else if (forceAsync) {
+        action += 'Async';
     }
-    exec(successCallback, errorCallback, "Echo", action, [message]);
+
+    exec(successCallback, errorCallback, "Echo", action, args);
 };
 
 
@@ -5086,7 +5275,7 @@ function stringify(message) {
                 return "error JSON.stringify()ing argument: " + e;
             }
         } else {
-            return message.toString();
+            return (typeof message === "undefined") ? "undefined" : message.toString();
         }
     } catch (e) {
         return e.toString();
@@ -5100,10 +5289,20 @@ function stringify(message) {
 function wrappedMethod(console, method) {
     var origMethod = console[method];
 
-    return function(message) {
+    return function() {
+
+        var args = [].slice.call(arguments),
+            len = args.length,
+            i = 0,
+            res = [];
+
+        for ( ; i < len; i++) {
+            res.push(stringify(args[i]));
+        }
+
         exec(null, null,
             'Debug Console', 'log',
-            [ stringify(message), { logLevel: method.toUpperCase() } ]
+            [ res.join(' '), { logLevel: method.toUpperCase() } ]
         );
 
         if (!origMethod) return;
@@ -5572,6 +5771,7 @@ modulemapper.defaults('cordova/plugin/Connection', 'Connection');
 define("cordova/plugin/notification", function(require, exports, module) {
 
 var exec = require('cordova/exec');
+var platform = require('cordova/platform');
 
 /**
  * Provides access to notifications on the device.
@@ -5600,15 +5800,53 @@ module.exports = {
      * @param {String} message              Message to print in the body of the alert
      * @param {Function} resultCallback     The callback that is called when user clicks on a button.
      * @param {String} title                Title of the alert dialog (default: Confirm)
-     * @param {String} buttonLabels         Comma separated list of the labels of the buttons (default: 'OK,Cancel')
+     * @param {Array} buttonLabels          Array of the labels of the buttons (default: ['OK', 'Cancel'])
      */
     confirm: function(message, resultCallback, title, buttonLabels) {
         var _title = (title || "Confirm");
-        var _buttonLabels = (buttonLabels || "OK,Cancel");
+        var _buttonLabels = (buttonLabels || ["OK", "Cancel"]);
+
+        // Strings are deprecated!
+        if (typeof _buttonLabels === 'string') {
+            console.log("Notification.confirm(string, function, string, string) is deprecated.  Use Notification.confirm(string, function, string, array).");
+        }
+
+        // Android and iOS take an array of button label names.
+        // Other platforms take a comma separated list.
+        // For compatibility, we convert to the desired type based on the platform.
+        if (platform.id == "android" || platform.id == "ios") {
+            if (typeof _buttonLabels === 'string') {
+                var buttonLabelString = _buttonLabels;
+                _buttonLabels = buttonLabelString.split(",");
+            }
+        } else {
+            if (Array.isArray(_buttonLabels)) {
+                var buttonLabelArray = _buttonLabels;
+                _buttonLabels = buttonLabelArray.toString();
+            }
+        }
         exec(resultCallback, null, "Notification", "confirm", [message, _title, _buttonLabels]);
     },
 
     /**
+     * Open a native prompt dialog, with a customizable title and button text.
+     * The following results are returned to the result callback:
+     *  buttonIndex     Index number of the button selected.
+     *  input1          The text entered in the prompt dialog box.
+     *
+     * @param {String} message              Dialog message to display (default: "Prompt message")
+     * @param {Function} resultCallback     The callback that is called when user clicks on a button.
+     * @param {String} title                Title of the dialog (default: "Prompt")
+     * @param {Array} buttonLabels          Array of strings for the button labels (default: ["OK","Cancel"])
+     */
+    prompt: function(message, resultCallback, title, buttonLabels) {
+        var _message = (message || "Prompt message");
+        var _title = (title || "Prompt");
+        var _buttonLabels = (buttonLabels || ["OK","Cancel"]);
+        exec(resultCallback, null, "Notification", "prompt", [_message, _title, _buttonLabels]);
+    },
+
+    /**
      * Causes the device to vibrate.
      *
      * @param {Integer} mills       The number of milliseconds to vibrate for.
@@ -6031,53 +6269,160 @@ window.cordova = require('cordova');
 (function (context) {
     // 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.
-    if (context.navigator) {
+    function replaceNavigator(origNavigator) {
         var CordovaNavigator = function() {};
-        CordovaNavigator.prototype = context.navigator;
-        context.navigator = new CordovaNavigator();
+        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 (context.navigator) {
+        context.navigator = replaceNavigator(context.navigator);
     }
 
-    var channel = require("cordova/channel"),
-        _self = {
-            boot: function () {
-                /**
-                 * Create all cordova objects once page has fully loaded and native side is ready.
-                 */
-                channel.join(function() {
-                    var builder = require('cordova/builder'),
-                        platform = require('cordova/platform');
+    var channel = require("cordova/channel");
+
+    // _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();
+    }
+
+    /**
+     * Create all cordova objects once page has fully loaded and native side is ready.
+     */
+    channel.join(function() {
+        var builder = require('cordova/builder'),
+            platform = require('cordova/platform');
+
+        builder.buildIntoButDoNotClobber(platform.defaults, context);
+        builder.buildIntoAndClobber(platform.clobbers, context);
+        builder.buildIntoAndMerge(platform.merges, context);
+
+        // Call the platform-specific initialization
+        platform.initialize();
+
+        // Fire event to notify that all objects are created
+        channel.onCordovaReady.fire();
+
+        // Fire onDeviceReady event once all constructors have run and
+        // cordova info has been received from native side.
+        channel.join(function() {
+            require('cordova').fireDocumentEvent('deviceready');
+        }, channel.deviceReadyChannelsArray);
+
+    }, [ channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady ]);
+
+}(window));
+
+// file: lib/scripts/plugin_loader.js
 
-                    builder.buildIntoButDoNotClobber(platform.defaults, context);
-                    builder.buildIntoAndClobber(platform.clobbers, context);
-                    builder.buildIntoAndMerge(platform.merges, context);
+// 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.
+(function (context) {
+    // To be populated with the handler by handlePluginsObject.
+    var onScriptLoadingComplete;
+
+    var scriptCounter = 0;
+    function scriptLoadedCallback() {
+        scriptCounter--;
+        if (scriptCounter === 0) {
+            onScriptLoadingComplete && onScriptLoadingComplete();
+        }
+    }
+
+    // Helper function to inject a <script> tag.
+    function injectScript(path) {
+        scriptCounter++;
+        var script = document.createElement("script");
+        script.onload = scriptLoadedCallback;
+        script.src = path;
+        document.head.appendChild(script);
+    }
 
-                    // Call the platform-specific initialization
-                    platform.initialize();
+    // Called when:
+    // * There are plugins defined and all plugins are finished loading.
+    // * There are no plugins to load.
+    function finishPluginLoading() {
+        context.cordova.require('cordova/channel').onPluginsReady.fire();
+    }
 
-                    // Fire event to notify that all objects are created
-                    channel.onCordovaReady.fire();
+    // Handler for the cordova_plugins.json 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 XHR response handler will just call finishPluginLoading().
+    function handlePluginsObject(modules) {
+        // First create the callback for when all plugins are loaded.
+        var mapper = context.cordova.require('cordova/modulemapper');
+        onScriptLoadingComplete = function() {
+            // Loop through all the plugins and then through their clobbers and merges.
+            for (var i = 0; i < modules.length; i++) {
+                var module = modules[i];
+                if (!module) continue;
+
+                if (module.clobbers && module.clobbers.length) {
+                    for (var j = 0; j < module.clobbers.length; j++) {
+                        mapper.clobbers(module.id, module.clobbers[j]);
+                    }
+                }
 
-                    // Fire onDeviceReady event once all constructors have run and
-                    // cordova info has been received from native side.
-                    channel.join(function() {
-                        require('cordova').fireDocumentEvent('deviceready');
-                    }, channel.deviceReadyChannelsArray);
+                if (module.merges && module.merges.length) {
+                    for (var k = 0; k < module.merges.length; k++) {
+                        mapper.merges(module.id, module.merges[k]);
+                    }
+                }
 
-                }, [ channel.onDOMContentLoaded, channel.onNativeReady ]);
+                // 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)) {
+                    context.cordova.require(module.id);
+                }
             }
-        };
 
-    // boot up once native side is ready
-    channel.onNativeReady.subscribe(_self.boot);
+            finishPluginLoading();
+        };
 
-    // _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();
+        // Now inject the scripts.
+        for (var i = 0; i < modules.length; i++) {
+            injectScript(modules[i].file);
+        }
     }
 
+    // Try to XHR the cordova_plugins.json file asynchronously.
+    var xhr = new context.XMLHttpRequest();
+    xhr.onreadystatechange = function() {
+        if (this.readyState != 4) { // not DONE
+            return;
+        }
+
+        // If the response is a JSON string which composes an array, call handlePluginsObject.
+        // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
+        if (this.status == 200) {
+            var obj = JSON.parse(this.responseText);
+            if (obj && obj instanceof Array && obj.length > 0) {
+                handlePluginsObject(obj);
+            } else {
+                finishPluginLoading();
+            }
+        } else {
+            finishPluginLoading();
+        }
+    };
+    xhr.open('GET', 'cordova_plugins.json', true); // Async
+    xhr.send();
 }(window));
 
 
+
 })();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLibTests/CDVFakeFileManager.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/CDVFakeFileManager.h b/lib/cordova-ios/CordovaLibTests/CDVFakeFileManager.h
index 41e5523..f9300a0 100644
--- a/lib/cordova-ios/CordovaLibTests/CDVFakeFileManager.h
+++ b/lib/cordova-ios/CordovaLibTests/CDVFakeFileManager.h
@@ -19,7 +19,7 @@
 
 #import <Foundation/Foundation.h>
 
-typedef BOOL (^CDVFileExistsBlock)(NSString*);
+typedef BOOL (^ CDVFileExistsBlock)(NSString*);
 
 // Used in place of an NSFileManager for unit tests. It implements only those functions
 // which are required by the tests that use it.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLibTests/CDVFileTransferTests.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/CDVFileTransferTests.m b/lib/cordova-ios/CordovaLibTests/CDVFileTransferTests.m
index 7488a5a..2effc98 100644
--- a/lib/cordova-ios/CordovaLibTests/CDVFileTransferTests.m
+++ b/lib/cordova-ios/CordovaLibTests/CDVFileTransferTests.m
@@ -140,15 +140,15 @@ static NSData *readStream(NSInputStream* stream)
 - (void)testEscapePathComponentForUrlString
 {
     STAssertTrue([@"" isEqualToString:
-            [_fileTransfer escapePathComponentForUrlString:@""]], nil);
+        [_fileTransfer escapePathComponentForUrlString:@""]], nil);
     STAssertTrue([@"foo" isEqualToString:
-            [_fileTransfer escapePathComponentForUrlString:@"foo"]], nil);
+        [_fileTransfer escapePathComponentForUrlString:@"foo"]], nil);
     STAssertTrue([@"http://a.org/spa%20ce%25" isEqualToString:
-            [_fileTransfer escapePathComponentForUrlString:@"http://a.org/spa ce%"]], nil);
+        [_fileTransfer escapePathComponentForUrlString:@"http://a.org/spa ce%"]], nil);
     STAssertTrue([@"http://a.org/spa%20ce%25/" isEqualToString:
-            [_fileTransfer escapePathComponentForUrlString:@"http://a.org/spa ce%/"]], nil);
+        [_fileTransfer escapePathComponentForUrlString:@"http://a.org/spa ce%/"]], nil);
     STAssertTrue([@"http://a.org/%25/%25/" isEqualToString:
-            [_fileTransfer escapePathComponentForUrlString:@"http://a.org/%/%/"]], nil);
+        [_fileTransfer escapePathComponentForUrlString:@"http://a.org/%/%/"]], nil);
 }
 
 - (void)testUpload_invalidServerUrl
@@ -208,7 +208,7 @@ static NSData *readStream(NSInputStream* stream)
 {
     [self setChunkedModeArg:NO];
     [self setHeaders:[NSDictionary dictionaryWithObjectsAndKeys:@"val1", @"key1",
-            [NSArray arrayWithObjects:@"val2a", @"val2b", nil], @"key2", [NSNull null], @"X-Requested-With", nil]];
+    [NSArray arrayWithObjects:@"val2a", @"val2b", nil], @"key2", [NSNull null], @"X-Requested-With", nil]];
     NSURLRequest* request = [self requestForUpload];
     STAssertTrue([@"val1" isEqualToString:[request valueForHTTPHeaderField:@"key1"]], nil);
     STAssertTrue([@"val2a,val2b" isEqualToString:[request valueForHTTPHeaderField:@"key2"]], nil);


[38/43] [CB-3238] Update cordova-android to 2.7.0

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/log.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/log.bat b/lib/cordova-android/bin/templates/cordova/log.bat
index 2c492e7..b8cc6be 100644
--- a/lib/cordova-android/bin/templates/cordova/log.bat
+++ b/lib/cordova-android/bin/templates/cordova/log.bat
@@ -1,2 +1,18 @@
-@ECHO OFF
-%~dp0\cordova.bat log %*
+:: 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.
+
+%~dp0\cordova.bat log

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/release
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/release b/lib/cordova-android/bin/templates/cordova/release
new file mode 100755
index 0000000..73d873e
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/release
@@ -0,0 +1,24 @@
+# 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.
+
+#!/bin/bash
+
+set -e
+
+CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
+
+bash "$CORDOVA_PATH"/cordova release

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/run
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/run b/lib/cordova-android/bin/templates/cordova/run
index ec352b0..840a8d5 100755
--- a/lib/cordova-android/bin/templates/cordova/run
+++ b/lib/cordova-android/bin/templates/cordova/run
@@ -1,4 +1,3 @@
-#!/bin/bash
 # 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
@@ -16,8 +15,10 @@
 # specific language governing permissions and limitations
 # under the License.
 
+#!/bin/bash
+
 set -e
 
 CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
 
-bash "$CORDOVA_PATH"/lib/cordova run "$@"
+bash "$CORDOVA_PATH"/cordova run

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/run.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/run.bat b/lib/cordova-android/bin/templates/cordova/run.bat
index b1cab64..7c470ed 100644
--- a/lib/cordova-android/bin/templates/cordova/run.bat
+++ b/lib/cordova-android/bin/templates/cordova/run.bat
@@ -1,2 +1 @@
-@ECHO OFF
-%~dp0\cordova.bat run %*
\ No newline at end of file
+%~dp0\cordova.bat run

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/project/assets/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/project/assets/www/index.html b/lib/cordova-android/bin/templates/project/assets/www/index.html
index 4d39cf3..564ce18 100644
--- a/lib/cordova-android/bin/templates/project/assets/www/index.html
+++ b/lib/cordova-android/bin/templates/project/assets/www/index.html
@@ -33,7 +33,7 @@
                 <p class="event received">Device is Ready</p>
             </div>
         </div>
-        <script type="text/javascript" src="cordova-2.6.0.js"></script>
+        <script type="text/javascript" src="cordova-2.7.0.js"></script>
         <script type="text/javascript" src="js/index.js"></script>
         <script type="text/javascript">
             app.initialize();

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/update
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/update b/lib/cordova-android/bin/update
index 92ceda8..0e86886 100755
--- a/lib/cordova-android/bin/update
+++ b/lib/cordova-android/bin/update
@@ -130,17 +130,10 @@ else
 fi
 
 # creating cordova folder and copying run/build/log/launch scripts
-mkdir "$PROJECT_PATH"/cordova
-mkdir "$PROJECT_PATH"/cordova/lib
 cp "$BUILD_PATH"/bin/templates/cordova/appinfo.jar "$PROJECT_PATH"/cordova/appinfo.jar
+cp "$BUILD_PATH"/bin/templates/cordova/cordova "$PROJECT_PATH"/cordova/cordova
 cp "$BUILD_PATH"/bin/templates/cordova/build "$PROJECT_PATH"/cordova/build
+cp "$BUILD_PATH"/bin/templates/cordova/release "$PROJECT_PATH"/cordova/release
 cp "$BUILD_PATH"/bin/templates/cordova/clean "$PROJECT_PATH"/cordova/clean
 cp "$BUILD_PATH"/bin/templates/cordova/log "$PROJECT_PATH"/cordova/log
 cp "$BUILD_PATH"/bin/templates/cordova/run "$PROJECT_PATH"/cordova/run
-cp "$BUILD_PATH"/bin/templates/cordova/lib/cordova "$PROJECT_PATH"/cordova/lib/cordova
-cp "$BUILD_PATH"/bin/templates/cordova/lib/install-device "$PROJECT_PATH"/cordova/lib/install-device
-cp "$BUILD_PATH"/bin/templates/cordova/lib/install-emulator "$PROJECT_PATH"/cordova/lib/install-emulator
-cp "$BUILD_PATH"/bin/templates/cordova/lib/list-devices "$PROJECT_PATH"/cordova/lib/list-devices
-cp "$BUILD_PATH"/bin/templates/cordova/lib/list-emulator-images "$PROJECT_PATH"/cordova/lib/list-emulator-images
-cp "$BUILD_PATH"/bin/templates/cordova/lib/list-started-emulators "$PROJECT_PATH"/cordova/lib/list-started-emulators
-cp "$BUILD_PATH"/bin/templates/cordova/lib/start-emulator "$PROJECT_PATH"/cordova/lib/start-emulator

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/update.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/update.js b/lib/cordova-android/bin/update.js
index 748d602..244dcc1 100644
--- a/lib/cordova-android/bin/update.js
+++ b/lib/cordova-android/bin/update.js
@@ -183,17 +183,11 @@ if(fso.FolderExists(ROOT + '\\framework')) {
 createAppInfoJar();
 WScript.Echo("Copying cordova command tools...");
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\appinfo.jar ' + PROJECT_PATH + '\\cordova\\appinfo.jar /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\cordova.js ' + PROJECT_PATH + '\\cordova\\cordova.js /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\cordova.bat ' + PROJECT_PATH + '\\cordova\\cordova.bat /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\clean.bat ' + PROJECT_PATH + '\\cordova\\clean.bat /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\build.bat ' + PROJECT_PATH + '\\cordova\\build.bat /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\log.bat ' + PROJECT_PATH + '\\cordova\\log.bat /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\run.bat ' + PROJECT_PATH + '\\cordova\\run.bat /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\cordova.js ' + PROJECT_PATH + '\\cordova\\lib\\cordova.js /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\install-device.bat ' + PROJECT_PATH + '\\cordova\\lib\\install-device.bat /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\install-emulator.bat ' + PROJECT_PATH + '\\cordova\\lib\\install-emulator.bat /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\list-emulator-images.bat ' + PROJECT_PATH + '\\cordova\\lib\\list-emulator-images.bat /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\list-devices.bat ' + PROJECT_PATH + '\\cordova\\lib\\list-devices.bat /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\list-started-emulators.bat ' + PROJECT_PATH + '\\cordova\\lib\\list-started-emulators.bat /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\start-emulator.bat ' + PROJECT_PATH + '\\cordova\\lib\\start-emulator.bat /Y');
 
 cleanup();

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/framework/assets/js/cordova.android.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/assets/js/cordova.android.js b/lib/cordova-android/framework/assets/js/cordova.android.js
index 2941307..ec1a2de 100644
--- a/lib/cordova-android/framework/assets/js/cordova.android.js
+++ b/lib/cordova-android/framework/assets/js/cordova.android.js
@@ -1,8 +1,8 @@
 // Platform: android
 
-// commit d0ffb852378ff018bac2f3b12c38098a19b8ce00
+// commit cd29cf0f224ccf25e9d422a33fd02ef67d3a78f4
 
-// File generated at :: Thu Apr 18 2013 15:10:54 GMT-0400 (EDT)
+// File generated at :: Thu Apr 25 2013 14:53:10 GMT-0700 (PDT)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -6813,7 +6813,7 @@ require('cordova/channel').onNativeReady.fire();
         xhr.onload = function() {
             // If the response is a JSON string which composes an array, call handlePluginsObject.
             // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
-            var obj = JSON.parse(this.responseText);
+            var obj = this.responseText && JSON.parse(this.responseText);
             if (obj && obj instanceof Array && obj.length > 0) {
                 handlePluginsObject(obj);
             } else {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/framework/assets/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/assets/www/index.html b/lib/cordova-android/framework/assets/www/index.html
index 1caeb8a..7723a7b 100644
--- a/lib/cordova-android/framework/assets/www/index.html
+++ b/lib/cordova-android/framework/assets/www/index.html
@@ -19,7 +19,7 @@
 <html>
   <head>
     <title></title>
-    <script src="cordova-2.6.0.js"></script>
+    <script src="cordova-2.7.0.js"></script>
   </head>
   <body>
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/framework/src/org/apache/cordova/Device.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/Device.java b/lib/cordova-android/framework/src/org/apache/cordova/Device.java
index aa316c5..dd3bdd4 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/Device.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/Device.java
@@ -38,7 +38,7 @@ import android.telephony.TelephonyManager;
 public class Device extends CordovaPlugin {
     public static final String TAG = "Device";
 
-    public static String cordovaVersion = "2.6.0";              // Cordova version
+    public static String cordovaVersion = "2.7.0";              // Cordova version
     public static String platform = "Android";                  // Device OS
     public static String uuid;                                  // Device UUID
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java b/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
index 375282e..847972e 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
@@ -43,13 +43,12 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
 
     @Override
     public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
-        if(url.contains("?") || url.contains("#") || needsIceCreamSpaceInAssetUrlFix(url)){
-            WebResourceResponse ret = generateWebResourceResponse(url);
-            if (ret != null) {
-                return ret;
-            }
+        //Check if plugins intercept the request
+        WebResourceResponse ret = super.shouldInterceptRequest(view, url);
+        if(ret == null && (url.contains("?") || url.contains("#") || needsIceCreamSpaceInAssetUrlFix(url))){
+            ret = generateWebResourceResponse(url);
         }
-        return super.shouldInterceptRequest(view, url);
+        return ret;
     }
 
     private WebResourceResponse generateWebResourceResponse(String url) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java b/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
index 7d823cd..774b21c 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
@@ -119,7 +119,6 @@ public class PluginManager {
                     service = xml.getAttributeValue(null, "name");
                     pluginClass = xml.getAttributeValue(null, "value");
                     // System.out.println("Plugin: "+name+" => "+value);
-                    Log.d(TAG, "<plugin> tags are deprecated, please use <features> instead. <plugin> will no longer work as of Cordova 3.0");
                     onload = "true".equals(xml.getAttributeValue(null, "onload"));
                     entry = new PluginEntry(service, pluginClass, onload);
                     this.addService(entry);


[36/43] git commit: Version 2.7.0-rc.1

Posted by an...@apache.org.
Version 2.7.0-rc.1


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

Branch: refs/heads/master
Commit: 71fb37252756f7952262a61cc72e987f860cb25a
Parents: d277668
Author: Michael Brooks <mi...@michaelbrooks.ca>
Authored: Tue Apr 23 09:48:13 2013 -0700
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu May 9 15:03:57 2013 -0700

----------------------------------------------------------------------
 VERSION                                            |    2 +-
 lib/cordova-android/.gitignore                     |   35 +
 lib/cordova-android/bin/check_reqs.bat             |    9 +
 lib/cordova-android/bin/check_reqs.js              |   81 ++
 lib/cordova-android/bin/create                     |   16 +-
 lib/cordova-android/bin/create.bat                 |   48 +-
 lib/cordova-android/bin/create.js                  |   81 ++-
 .../cordova/ApplicationInfo/ApplicationInfo.class  |  Bin 2045 -> 0 bytes
 .../bin/templates/cordova/appinfo.jar              |  Bin 1574 -> 0 bytes
 lib/cordova-android/bin/templates/cordova/build    |    5 +-
 .../bin/templates/cordova/build.bat                |   20 +-
 lib/cordova-android/bin/templates/cordova/clean    |    5 +-
 .../bin/templates/cordova/clean.bat                |   20 +-
 lib/cordova-android/bin/templates/cordova/cordova  |  159 ----
 .../bin/templates/cordova/cordova.bat              |    7 +-
 .../bin/templates/cordova/cordova.js               |  137 ----
 .../bin/templates/cordova/lib/cordova              |  386 ++++++++++
 .../bin/templates/cordova/lib/cordova.js           |  593 +++++++++++++++
 .../bin/templates/cordova/lib/install-device       |   23 +
 .../bin/templates/cordova/lib/install-device.bat   |    9 +
 .../bin/templates/cordova/lib/install-emulator     |   23 +
 .../bin/templates/cordova/lib/install-emulator.bat |    9 +
 .../bin/templates/cordova/lib/list-devices         |   23 +
 .../bin/templates/cordova/lib/list-devices.bat     |    9 +
 .../bin/templates/cordova/lib/list-emulator-images |   23 +
 .../templates/cordova/lib/list-emulator-images.bat |    9 +
 .../templates/cordova/lib/list-started-emulators   |   23 +
 .../cordova/lib/list-started-emulators.bat         |    9 +
 .../bin/templates/cordova/lib/start-emulator       |   23 +
 .../bin/templates/cordova/lib/start-emulator.bat   |    9 +
 lib/cordova-android/bin/templates/cordova/log      |    5 +-
 lib/cordova-android/bin/templates/cordova/log.bat  |   20 +-
 lib/cordova-android/bin/templates/cordova/release  |   24 -
 lib/cordova-android/bin/templates/cordova/run      |    5 +-
 lib/cordova-android/bin/templates/cordova/run.bat  |    3 +-
 lib/cordova-android/bin/update                     |   11 +-
 lib/cordova-android/bin/update.js                  |    8 +-
 .../framework/assets/js/cordova.android.js         |  378 ++++++----
 .../framework/libs/commons-codec-1.7.jar           |  Bin 259600 -> 0 bytes
 lib/cordova-android/framework/proguard-project.txt |   20 -
 .../src/org/apache/cordova/CameraLauncher.java     |   62 +-
 .../framework/src/org/apache/cordova/Config.java   |   24 +-
 .../apache/cordova/CordovaLocationListener.java    |   62 ++-
 .../src/org/apache/cordova/CordovaWebView.java     |   14 +-
 .../org/apache/cordova/CordovaWebViewClient.java   |    9 -
 .../framework/src/org/apache/cordova/Device.java   |    1 -
 .../framework/src/org/apache/cordova/DroidGap.java |   11 +-
 .../src/org/apache/cordova/ExposedJsApi.java       |    7 +
 .../src/org/apache/cordova/FileHelper.java         |   19 +-
 .../src/org/apache/cordova/FileTransfer.java       |  105 +++-
 .../src/org/apache/cordova/GeoBroker.java          |   18 +-
 .../cordova/IceCreamCordovaWebViewClient.java      |   35 +-
 .../src/org/apache/cordova/InAppBrowser.java       |  157 ++++-
 .../org/apache/cordova/NativeToJsMessageQueue.java |    9 +-
 .../src/org/apache/cordova/api/Plugin.java         |  177 -----
 .../src/org/apache/cordova/api/PluginManager.java  |    1 +
 lib/cordova-blackberry/.gitignore                  |   26 +
 lib/cordova-blackberry/VERSION                     |    2 +-
 lib/cordova-blackberry/bin/create                  |   10 +-
 .../project/lib/ant-contrib/ant-contrib-1.0b3.jar  |  Bin 224277 -> 0 bytes
 .../bin/templates/project/www/VERSION              |    2 +-
 .../bin/templates/project/www/index.html           |    2 +-
 .../ext/src/org/apache/cordova/device/Device.java  |    2 +-
 .../javascript/cordova.blackberry.js               |  327 +++++----
 lib/cordova-ios/.gitignore                         |   12 +
 lib/cordova-ios/.gitmodules                        |    3 +
 lib/cordova-ios/CordovaLib/Classes/CDV.h           |    2 +-
 .../CordovaLib/Classes/CDVAvailability.h           |    3 +-
 .../CordovaLib/Classes/CDVDebugConsole.h           |   28 -
 .../CordovaLib/Classes/CDVDebugConsole.m           |   37 -
 lib/cordova-ios/CordovaLib/Classes/CDVFile.m       |   11 +-
 .../CordovaLib/Classes/CDVFileTransfer.h           |    7 +
 .../CordovaLib/Classes/CDVFileTransfer.m           |  183 ++++--
 .../CordovaLib/Classes/CDVInAppBrowser.h           |   18 +-
 .../CordovaLib/Classes/CDVInAppBrowser.m           |  166 ++++-
 .../CordovaLib/Classes/CDVJpegHeaderWriter.m       |   53 +-
 lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h     |    8 +-
 lib/cordova-ios/CordovaLib/Classes/CDVSound.m      |    3 +
 lib/cordova-ios/CordovaLib/Classes/CDVTimer.h      |   27 +
 lib/cordova-ios/CordovaLib/Classes/CDVTimer.m      |  123 +++
 .../CordovaLib/Classes/CDVViewController.m         |   58 +-
 .../CordovaLib/Classes/CDVWebViewDelegate.h        |    1 +
 .../CordovaLib/Classes/CDVWebViewDelegate.m        |  253 +++++--
 lib/cordova-ios/CordovaLib/Classes/CDVWhitelist.h  |    5 +-
 lib/cordova-ios/CordovaLib/Classes/CDVWhitelist.m  |   95 ++-
 .../CordovaLib.xcodeproj/project.pbxproj           |   16 +-
 lib/cordova-ios/CordovaLib/VERSION                 |    2 +-
 lib/cordova-ios/CordovaLib/cordova.ios.js          |  422 +++++------
 .../CordovaLibTests/CDVWhitelistTests.m            |   22 +-
 .../CordovaLibTests/CordovaLibApp/config.xml       |    1 -
 lib/cordova-ios/RELEASENOTES.md                    |   39 +
 lib/cordova-ios/bin/check_reqs                     |   34 +
 .../project/__TESTING__.xcodeproj/project.pbxproj  |    2 +-
 .../project/__TESTING__/Classes/AppDelegate.m      |   18 +-
 .../bin/templates/project/__TESTING__/config.xml   |    1 -
 package.json                                       |    2 +-
 96 files changed, 3413 insertions(+), 1594 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/VERSION
----------------------------------------------------------------------
diff --git a/VERSION b/VERSION
index e70b452..59b7056 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.6.0
+2.7.0rc1

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/.gitignore
----------------------------------------------------------------------
diff --git a/lib/cordova-android/.gitignore b/lib/cordova-android/.gitignore
new file mode 100644
index 0000000..757a698
--- /dev/null
+++ b/lib/cordova-android/.gitignore
@@ -0,0 +1,35 @@
+.DS_Store
+default.properties
+gen
+assets/www/cordova.js
+framework/assets/www/.tmp*
+local.properties
+framework/lib
+proguard.cfg
+proguard.cfg
+proguard-project.txt
+framework/bin
+framework/test/org/apache/cordova/*.class
+framework/assets/www/.DS_Store
+framework/assets/www/cordova-*.js
+framework/assets/www/phonegap-*.js
+framework/libs
+test/libs
+example
+./test
+test/bin
+test/assets/www/.tmp*
+tmp/**
+bin/node_modules
+.metadata
+tmp/**/*
+Thumbs.db
+Desktop.ini
+*.tmp
+*.bak
+*.swp
+*.class
+*.jar
+# IntelliJ IDEA files
+*.iml
+.idea

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/check_reqs.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/check_reqs.bat b/lib/cordova-android/bin/check_reqs.bat
new file mode 100644
index 0000000..65514c8
--- /dev/null
+++ b/lib/cordova-android/bin/check_reqs.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%check_reqs.js (
+        cscript "%full_path%check_reqs.js" //nologo
+) ELSE (
+    ECHO.
+    ECHO ERROR: Could not find 'check_reqs.js' in 'bin' folder, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/check_reqs.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/check_reqs.js b/lib/cordova-android/bin/check_reqs.js
new file mode 100644
index 0000000..ef30991
--- /dev/null
+++ b/lib/cordova-android/bin/check_reqs.js
@@ -0,0 +1,81 @@
+// 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 ROOT  = WScript.ScriptFullName.split('\\bin\\check_reqs.js').join(''),
+    shell = WScript.CreateObject("WScript.Shell"),
+    fso   = WScript.CreateObject('Scripting.FileSystemObject');
+
+
+// executes a command in the shell, returns stdout or stderr if error
+function exec_out(command) {
+    var oExec=shell.Exec(command);
+    var output = new String();
+    while (oExec.Status == 0) {
+        if (!oExec.StdOut.AtEndOfStream) {
+            var line = oExec.StdOut.ReadAll();
+            // XXX: Change to verbose mode 
+            // WScript.StdOut.WriteLine(line);
+            output += line;
+        }
+        WScript.sleep(100);
+    }
+    //Check to make sure our scripts did not encounter an error
+    if (!oExec.StdErr.AtEndOfStream) {
+        var line = oExec.StdErr.ReadAll();
+        return {'error' : true, 'output' : line};
+    } else if (!oExec.StdOut.AtEndOfStream) {
+            var line = oExec.StdOut.ReadAll();
+            // XXX: Change to verbose mode 
+            // WScript.StdOut.WriteLine(line);
+            output += line;
+    }
+    return {'error' : false, 'output' : output};
+}
+
+// log to stdout or stderr
+function Log(msg, error) {
+    if (error) {
+        WScript.StdErr.WriteLine(msg);
+    }
+    else {
+        WScript.StdOut.WriteLine(msg);
+    }
+} 
+
+// checks that android requirements are met
+function check_requirements() {
+    var result = exec_out('%comspec% /c android list target');
+    if(result.error) {
+        Log('The command `android` failed. Make sure you have the latest Android SDK installed, and the `android` command (inside the tools/ folder) added to your path. Output: ' + result.output, true);
+        WScript.Quit(2);
+    }
+    else if(!result.output.match(/android[-]17/)) {
+        Log('Please install Android target 17 (the Android 4.2 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.', true);
+        Log('Output : ' + result.output);
+        WScript.Quit(2);
+    }
+    else {
+        var cmd = '%comspec% /c android update project -p ' + ROOT + '\\framework -t android-17';
+        result = exec_out(cmd);
+        if(result.error) {
+            Log('Error updating the Cordova library to work with your Android environment. Command run: "' + cmd + '", output: ' + result.output, true);
+            WScript.Quit(2);  
+        }
+    }
+}
+
+check_requirements();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/create
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/create b/lib/cordova-android/bin/create
index 2eae82b..b7e96b4 100755
--- a/lib/cordova-android/bin/create
+++ b/lib/cordova-android/bin/create
@@ -25,8 +25,11 @@ set -e
 
 if [ -z "$1" ] || [ "$1" == "-h" ]
 then
-    echo 'usage: create path package activity'
+    echo "Usage: $0 <path_to_new_project> <package_name> <project_name>"
     echo "Make sure the Android SDK tools folder is in your PATH!"
+    echo "    <path_to_new_project>: Path to your new Cordova iOS project"
+    echo "    <package_name>: Package name, following reverse-domain style convention"
+    echo "    <project_name>: Project name"
     exit 0
 fi
 
@@ -158,11 +161,18 @@ replace "s/__APILEVEL__/${API_LEVEL}/g" "$MANIFEST_PATH"
 
 # creating cordova folder and copying run/build/log/launch scripts
 mkdir "$PROJECT_PATH"/cordova
+mkdir "$PROJECT_PATH"/cordova/lib
 createAppInfoJar
 cp "$BUILD_PATH"/bin/templates/cordova/appinfo.jar "$PROJECT_PATH"/cordova/appinfo.jar
-cp "$BUILD_PATH"/bin/templates/cordova/cordova "$PROJECT_PATH"/cordova/cordova
 cp "$BUILD_PATH"/bin/templates/cordova/build "$PROJECT_PATH"/cordova/build
-cp "$BUILD_PATH"/bin/templates/cordova/release "$PROJECT_PATH"/cordova/release
 cp "$BUILD_PATH"/bin/templates/cordova/clean "$PROJECT_PATH"/cordova/clean
 cp "$BUILD_PATH"/bin/templates/cordova/log "$PROJECT_PATH"/cordova/log
 cp "$BUILD_PATH"/bin/templates/cordova/run "$PROJECT_PATH"/cordova/run
+cp "$BUILD_PATH"/bin/templates/cordova/lib/cordova "$PROJECT_PATH"/cordova/lib/cordova
+cp "$BUILD_PATH"/bin/templates/cordova/lib/install-device "$PROJECT_PATH"/cordova/lib/install-device
+cp "$BUILD_PATH"/bin/templates/cordova/lib/install-emulator "$PROJECT_PATH"/cordova/lib/install-emulator
+cp "$BUILD_PATH"/bin/templates/cordova/lib/list-devices "$PROJECT_PATH"/cordova/lib/list-devices
+cp "$BUILD_PATH"/bin/templates/cordova/lib/list-emulator-images "$PROJECT_PATH"/cordova/lib/list-emulator-images
+cp "$BUILD_PATH"/bin/templates/cordova/lib/list-started-emulators "$PROJECT_PATH"/cordova/lib/list-started-emulators
+cp "$BUILD_PATH"/bin/templates/cordova/lib/start-emulator "$PROJECT_PATH"/cordova/lib/start-emulator
+

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/create.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/create.bat b/lib/cordova-android/bin/create.bat
index 35fdc3b..7f0346f 100644
--- a/lib/cordova-android/bin/create.bat
+++ b/lib/cordova-android/bin/create.bat
@@ -1,3 +1,5 @@
+@ECHO OFF
+GOTO BEGIN
 :: 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
@@ -15,18 +17,38 @@
 :: specific language governing permissions and limitations
 :: under the License.
 
-@ECHO OFF
-IF NOT DEFINED JAVA_HOME GOTO MISSING
-FOR %%X in (java.exe javac.exe ant.bat android.bat) do (
-    SET FOUND=%%~$PATH:X
-    IF NOT DEFINED FOUND GOTO MISSING
-)
-cscript "%~dp0\create.js" %*
-GOTO END
-:MISSING
-ECHO Missing one of the following:
-ECHO JDK: http://java.oracle.com
-ECHO Android SDK: http://developer.android.com
-ECHO Apache ant: http://ant.apache.org
+:BEGIN
+        IF NOT DEFINED JAVA_HOME GOTO MISSING_JAVA_HOME
+
+        FOR %%X in (java.exe javac.exe ant.bat android.bat) do (
+            IF [%%~$PATH:X]==[] (
+              ECHO Cannot locate %%X using the PATH environment variable.
+              ECHO Retry after adding directory containing %%X to the PATH variable.
+              ECHO Remember to open a new command window after updating the PATH variable.
+              IF "%%X"=="java.exe" GOTO GET_JAVA
+              IF "%%X"=="javac.exe" GOTO GET_JAVA
+              IF "%%X"=="ant.bat" GOTO GET_ANT
+              IF "%%X"=="android.bat" GOTO GET_ANDROID
+              GOTO ERROR
+            )
+        )
+        cscript "%~dp0\create.js" %* //nologo
+        GOTO END
+:MISSING_JAVA_HOME
+        ECHO The JAVA_HOME environment variable is not set.
+        ECHO Set JAVA_HOME to an existing JRE directory.
+        ECHO Remember to also add JAVA_HOME to the PATH variable.
+        ECHO After updating system variables, open a new command window and retry.
+        GOTO ERROR
+:GET_JAVA
+        ECHO Visit http://java.oracle.com if you need to install Java (JDK).
+        GOTO ERROR
+:GET_ANT
+        ECHO Visit http://ant.apache.org if you need to install Apache Ant.
+        GOTO ERROR
+:GET_ANDROID
+        ECHO Visit http://developer.android.com if you need to install the Android SDK.
+        GOTO ERROR
+:ERROR
 EXIT /B 1
 :END

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/create.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/create.js b/lib/cordova-android/bin/create.js
index d0d9999..5176b7d 100644
--- a/lib/cordova-android/bin/create.js
+++ b/lib/cordova-android/bin/create.js
@@ -24,7 +24,30 @@
  *  ./create [path package activity]
  */
 
-var fso = WScript.CreateObject('Scripting.FileSystemObject');
+var args = WScript.Arguments, PROJECT_PATH="example", 
+    PACKAGE="org.apache.cordova.example", ACTIVITY="cordovaExample",
+    shell=WScript.CreateObject("WScript.Shell"),
+    fso = WScript.CreateObject('Scripting.FileSystemObject');
+
+function Usage() {
+    Log("Usage: create PathTONewProject [ PackageName AppName ]");
+    Log("    PathTONewProject : The path to where you wish to create the project");
+    Log("    PackageName      : The package for the project (default is org.apache.cordova.example)")
+    Log("    AppName          : The name of the application/activity (default is cordovaExample)");
+    Log("examples:");
+    Log("    create C:\\Users\\anonymous\\Desktop\\MyProject");
+    Log("    create C:\\Users\\anonymous\\Desktop\\MyProject io.Cordova.Example AnApp");
+}
+
+// logs messaged to stdout and stderr
+function Log(msg, error) {
+    if (error) {
+        WScript.StdErr.WriteLine(msg);
+    }
+    else {
+        WScript.StdOut.WriteLine(msg);
+    }
+}
 
 function read(filename) {
     var fso=WScript.CreateObject("Scripting.FileSystemObject");
@@ -36,7 +59,7 @@ function read(filename) {
 
 function checkTargets(targets) {
     if(!targets) {
-        WScript.Echo("You do not have any android targets setup. Please create at least one target with the `android` command");
+        Log("You do not have any android targets setup. Please create at least one target with the `android` command", true);
         WScript.Quit(69);
     }
 }
@@ -74,7 +97,7 @@ function exec(command) {
 
 function createAppInfoJar() {
     if(!fso.FileExists(ROOT+"\\bin\\templates\\cordova\\appinfo.jar")) {
-        WScript.Echo("Creating appinfo.jar...");
+        Log("Creating appinfo.jar...");
         var cur = shell.CurrentDirectory;
         shell.CurrentDirectory = ROOT+"\\bin\\templates\\cordova\\ApplicationInfo";
         exec("javac ApplicationInfo.java");
@@ -120,7 +143,7 @@ function downloadCommonsCodec() {
           stream.SaveToFile(savePath);
           stream.Close();
         } else {
-          WScript.Echo('Could not retrieve the commons-codec. Please download it yourself and put into the framework/libs directory. This process may fail now. Sorry.');
+          Log('Could not retrieve the commons-codec. Please download it yourself and put into the framework/libs directory. This process may fail now. Sorry.');
         }
       }
       var app = WScript.CreateObject('Shell.Application');
@@ -136,23 +159,34 @@ function downloadCommonsCodec() {
       fso.DeleteFolder(ROOT + '\\framework\\libs\\commons-codec-1.7', true);
     }
 }
-
-var args = WScript.Arguments, PROJECT_PATH="example", 
-    PACKAGE="org.apache.cordova.example", ACTIVITY="cordovaExample",
-    shell=WScript.CreateObject("WScript.Shell");
     
 // working dir
 var ROOT = WScript.ScriptFullName.split('\\bin\\create.js').join('');
+if (args.Count() > 0) {
+    // support help flags
+    if (args(0) == "--help" || args(0) == "/?" ||
+            args(0) == "help" || args(0) == "-help" || args(0) == "/help" || args(0) == "-h") {
+        Usage();
+        WScript.Quit(2);
+    }
 
-if (args.Count() == 3) {
     PROJECT_PATH=args(0);
-    PACKAGE=args(1);
-    ACTIVITY=args(2);
+    if (args.Count() > 1) {
+        PACKAGE = args(1);
+    }
+    if (args.Count() > 2) {
+        ACTIVITY = args(2);
+    }
+}
+else {
+    Log("Error : No project path provided.");
+    Usage();
+    WScript.Quit(2);
 }
 
 if(fso.FolderExists(PROJECT_PATH)) {
-    WScript.Echo("Project already exists!");
-    WScript.Quit(1);
+    Log("Project already exists!", true);
+    WScript.Quit(2);
 }
 
 var PACKAGE_AS_PATH=PACKAGE.replace(/\./g, '\\');
@@ -162,13 +196,13 @@ var TARGET=setTarget();
 var API_LEVEL=setApiLevel();
 var VERSION=read(ROOT+'\\VERSION').replace(/\r\n/,'').replace(/\n/,'');
 // create the project
-WScript.Echo("Creating new android project...");
+Log("Creating new android project...");
 exec('android.bat create project --target '+TARGET+' --path '+PROJECT_PATH+' --package '+PACKAGE+' --activity '+ACTIVITY);
 
 // build from source. distro should have these files
 if (!fso.FileExists(ROOT+'\\cordova-'+VERSION+'.jar') &&
     !fso.FileExists(ROOT+'\\cordova-'+VERSION+'.js')) {
-    WScript.Echo("Building jar and js files...");
+    Log("Building jar and js files...");
     // update the cordova framework project to a target that exists on this machine
     exec('android.bat update project --target '+TARGET+' --path '+ROOT+'\\framework');
     // pull down commons codec if necessary
@@ -177,14 +211,14 @@ if (!fso.FileExists(ROOT+'\\cordova-'+VERSION+'.jar') &&
 }
 
 // copy in the project template
-WScript.Echo("Copying template files...");
+Log("Copying template files...");
 exec('%comspec% /c xcopy "'+ ROOT + '"\\bin\\templates\\project\\res '+PROJECT_PATH+'\\res\\ /E /Y');
 exec('%comspec% /c xcopy "'+ ROOT + '"\\bin\\templates\\project\\assets '+PROJECT_PATH+'\\assets\\ /E /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\project\\AndroidManifest.xml ' + PROJECT_PATH + '\\AndroidManifest.xml /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\project\\Activity.java '+ ACTIVITY_PATH +' /Y');
 
 // check if we have the source or the distro files
-WScript.Echo("Copying js, jar & config.xml files...");
+Log("Copying js, jar & config.xml files...");
 if(fso.FolderExists(ROOT + '\\framework')) {
     exec('%comspec% /c copy "'+ROOT+'"\\framework\\assets\\www\\cordova-'+VERSION+'.js '+PROJECT_PATH+'\\assets\\www\\cordova-'+VERSION+'.js /Y');
     exec('%comspec% /c copy "'+ROOT+'"\\framework\\cordova-'+VERSION+'.jar '+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar /Y');
@@ -202,10 +236,17 @@ if(fso.FolderExists(ROOT + '\\framework')) {
 
 // copy cordova scripts
 fso.CreateFolder(PROJECT_PATH + '\\cordova');
+fso.CreateFolder(PROJECT_PATH + '\\cordova\\lib');
 createAppInfoJar();
-WScript.Echo("Copying cordova command tools...");
+Log("Copying cordova command tools...");
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\appinfo.jar ' + PROJECT_PATH + '\\cordova\\appinfo.jar /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\cordova.js ' + PROJECT_PATH + '\\cordova\\cordova.js /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\cordova.js ' + PROJECT_PATH + '\\cordova\\lib\\cordova.js /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\install-device.bat ' + PROJECT_PATH + '\\cordova\\lib\\install-device.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\install-emulator.bat ' + PROJECT_PATH + '\\cordova\\lib\\install-emulator.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\list-emulator-images.bat ' + PROJECT_PATH + '\\cordova\\lib\\list-emulator-images.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\list-devices.bat ' + PROJECT_PATH + '\\cordova\\lib\\list-devices.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\list-started-emulators.bat ' + PROJECT_PATH + '\\cordova\\lib\\list-started-emulators.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\start-emulator.bat ' + PROJECT_PATH + '\\cordova\\lib\\start-emulator.bat /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\cordova.bat ' + PROJECT_PATH + '\\cordova\\cordova.bat /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\clean.bat ' + PROJECT_PATH + '\\cordova\\clean.bat /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\build.bat ' + PROJECT_PATH + '\\cordova\\build.bat /Y');
@@ -213,7 +254,7 @@ exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\log.bat ' + PROJECT
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\run.bat ' + PROJECT_PATH + '\\cordova\\run.bat /Y');
 
 // interpolate the activity name and package
-WScript.Echo("Updating AndroidManifest.xml and Main Activity...");
+Log("Updating AndroidManifest.xml and Main Activity...");
 replaceInFile(ACTIVITY_PATH, /__ACTIVITY__/, ACTIVITY);
 replaceInFile(ACTIVITY_PATH, /__ID__/, PACKAGE);
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/ApplicationInfo/ApplicationInfo.class
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/ApplicationInfo/ApplicationInfo.class b/lib/cordova-android/bin/templates/cordova/ApplicationInfo/ApplicationInfo.class
deleted file mode 100644
index 2ef42a4..0000000
Binary files a/lib/cordova-android/bin/templates/cordova/ApplicationInfo/ApplicationInfo.class and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/appinfo.jar
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/appinfo.jar b/lib/cordova-android/bin/templates/cordova/appinfo.jar
deleted file mode 100644
index 390bb6d..0000000
Binary files a/lib/cordova-android/bin/templates/cordova/appinfo.jar and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/build
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/build b/lib/cordova-android/bin/templates/cordova/build
index e586e4d..3cbd9c1 100755
--- a/lib/cordova-android/bin/templates/cordova/build
+++ b/lib/cordova-android/bin/templates/cordova/build
@@ -1,3 +1,4 @@
+#!/bin/bash
 # 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
@@ -15,10 +16,8 @@
 # specific language governing permissions and limitations
 # under the License.
 
-#!/bin/bash
-
 set -e
 
 CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
 
-bash "$CORDOVA_PATH"/cordova build
+bash "$CORDOVA_PATH"/lib/cordova build "$@"

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/build.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/build.bat b/lib/cordova-android/bin/templates/cordova/build.bat
index 8e6ca9a..7aa7c75 100644
--- a/lib/cordova-android/bin/templates/cordova/build.bat
+++ b/lib/cordova-android/bin/templates/cordova/build.bat
@@ -1,18 +1,2 @@
-:: 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.
-
-%~dp0\cordova.bat build
+@ECHO OFF
+%~dp0\cordova.bat build %*
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/clean
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/clean b/lib/cordova-android/bin/templates/cordova/clean
index 53b7f9a..f52966a 100755
--- a/lib/cordova-android/bin/templates/cordova/clean
+++ b/lib/cordova-android/bin/templates/cordova/clean
@@ -1,3 +1,4 @@
+#!/bin/bash
 # 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
@@ -15,10 +16,8 @@
 # specific language governing permissions and limitations
 # under the License.
 
-#!/bin/bash
-
 set -e
 
 CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
 
-bash "$CORDOVA_PATH"/cordova clean
+bash "$CORDOVA_PATH"/lib/cordova clean "$@"

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/clean.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/clean.bat b/lib/cordova-android/bin/templates/cordova/clean.bat
index fe5c09f..b41bdc9 100644
--- a/lib/cordova-android/bin/templates/cordova/clean.bat
+++ b/lib/cordova-android/bin/templates/cordova/clean.bat
@@ -1,18 +1,2 @@
-:: 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.
-
-%~dp0\cordova.bat clean
+@ECHO OFF
+%~dp0\cordova.bat clean %*

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/cordova
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/cordova b/lib/cordova-android/bin/templates/cordova/cordova
deleted file mode 100755
index 1945a4c..0000000
--- a/lib/cordova-android/bin/templates/cordova/cordova
+++ /dev/null
@@ -1,159 +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.
-
-#!/bin/bash
-
-
-PROJECT_PATH=$( cd "$( dirname "$0" )/.." && pwd )
-
-function check_devices {
-# FIXME
-    local devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep device`
-    if [ -z "$devices"  ] ; then
-        echo "1"
-    else
-        echo "0"
-    fi
-}
-
-function emulate {
-    declare -a avd_list=($(android list avd | grep "Name:" | cut -f 2 -d ":" | xargs))
-    # we need to start adb-server
-    adb start-server 1>/dev/null
-
-    # Do not launch an emulator if there is already one running or if a device is attached
-    if [ $(check_devices) == 0 ] ; then
-        return
-    fi
-
-    local avd_id="1000" #FIXME: hopefully user does not have 1000 AVDs
-    # User has no AVDs
-    if [ ${#avd_list[@]} == 0 ]
-    then
-        echo "You don't have any Android Virtual Devices. Please create at least one AVD."
-        echo "android"
-    fi
-    # User has only one AVD
-    if [ ${#avd_list[@]} == 1 ]
-    then
-        emulator -cpu-delay 0 -no-boot-anim -cache /tmp/cache -avd ${avd_list[0]} 1> /dev/null 2>&1 &
-    # User has more than 1 AVD
-    elif [ ${#avd_list[@]} -gt 1 ]
-    then
-        while [ -z ${avd_list[$avd_id]} ]
-        do
-            echo "Choose from one of the following Android Virtual Devices [0 to $((${#avd_list[@]}-1))]:"
-            for(( i = 0 ; i < ${#avd_list[@]} ; i++ ))
-            do
-                echo "$i) ${avd_list[$i]}"
-            done
-            read -t 5 -p "> " avd_id
-            # default value if input timeout
-            if [ $avd_id -eq 1000 ] ; then avd_id=0 ; fi
-        done
-        emulator -cpu-delay 0 -no-boot-anim -cache /tmp/cache -avd ${avd_list[$avd_id]} 1> /dev/null 2>&1 &
-    fi
-    
-}
-
-function clean {
-    ant clean
-}
-# has to be used independently and not in conjunction with other commands
-function log {
-    adb logcat
-}
-
-function run {
-    clean && emulate && wait_for_device && install && launch 
-}
-
-function install {
-    
-    declare -a devices=($(adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep device | cut -f 1))
-    local device_id="1000" #FIXME: hopefully user does not have 1000 AVDs
-    
-    if [ ${#devices[@]} == 0 ]
-    then
-        # should not reach here. Emulator should launch or device should be attached
-        echo "Emulator not running or device not attached. Could not install debug package"
-        exit 70
-    fi
-    
-    if [ ${#devices[@]} == 1 ]
-    then
-        export ANDROID_SERIAL=${devices[0]}
-    # User has more than 1 AVD
-    elif [ ${#devices[@]} -gt 1 ]
-    then
-        while [ -z ${devices[$device_id]} ]
-        do
-            echo "Choose from one of the following devices/emulators [0 to $((${#devices[@]}-1))]:"
-            for(( i = 0 ; i < ${#devices[@]} ; i++ ))
-            do
-                echo "$i) ${devices[$i]}"
-            done
-            read -t 5 -p "> " device_id
-            # default value if input timeout
-            if [ $device_id -eq 1000 ] ; then device_id=0 ; fi
-        done
-        export ANDROID_SERIAL=${devices[$device_id]}
-    fi
-
-    ant debug install
-}
-
-function build {
-    ant debug
-}
-
-function release {
-    ant release
-}
-
-function wait_for_device {
-    local i="0"
-    echo -n "Waiting for device..."
-
-    while [ $i -lt 300 ]
-    do
-        if [ $(check_devices) -eq 0 ]
-        then
-            break
-        else
-            sleep 1
-            i=$[i+1]
-            echo -n "."
-        fi
-    done
-    # Device timeout: emulator has not started in time or device not attached
-    if [ $i -eq 300 ]
-    then
-        echo "device timeout!"
-        exit 69
-    else
-        echo "connected!"
-    fi
-}
-
-function launch {
-    local launch_str=$(java -jar "$PROJECT_PATH"/cordova/appinfo.jar "$PROJECT_PATH"/AndroidManifest.xml)
-    adb shell am start -n $launch_str 
-}
-
-# TODO parse arguments
-(cd "$PROJECT_PATH" && $1)

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/cordova.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/cordova.bat b/lib/cordova-android/bin/templates/cordova/cordova.bat
index 22c289a..9b56199 100644
--- a/lib/cordova-android/bin/templates/cordova/cordova.bat
+++ b/lib/cordova-android/bin/templates/cordova/cordova.bat
@@ -1,3 +1,5 @@
+@ECHO OFF
+GOTO BEGIN
 :: 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
@@ -14,14 +16,13 @@
 :: KIND, either express or implied.  See the License for the
 :: specific language governing permissions and limitations
 :: under the License.
-
-@ECHO OFF
+:BEGIN
 IF NOT DEFINED JAVA_HOME GOTO MISSING
 FOR %%X in (java.exe ant.bat android.bat) do (
     SET FOUND=%%~$PATH:X
     IF NOT DEFINED FOUND GOTO MISSING
 )
-cscript %~dp0\cordova.js %*
+cscript %~dp0\lib\cordova.js %* //nologo
 GOTO END
 :MISSING
 ECHO Missing one of the following:

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/cordova.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/cordova.js b/lib/cordova-android/bin/templates/cordova/cordova.js
deleted file mode 100644
index 51533cb..0000000
--- a/lib/cordova-android/bin/templates/cordova/cordova.js
+++ /dev/null
@@ -1,137 +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 ROOT = WScript.ScriptFullName.split('\\cordova\\cordova.js').join(''),
-    shell=WScript.CreateObject("WScript.Shell");
-
-function exec(command) {
-    var oExec=shell.Exec(command);
-    var output = new String();
-    while(oExec.Status == 0) {
-        if(!oExec.StdOut.AtEndOfStream) {
-            var line = oExec.StdOut.ReadLine();
-            // XXX: Change to verbose mode 
-            // WScript.StdOut.WriteLine(line);
-            output += line;
-        }
-        WScript.sleep(100);
-    }
-
-    return output;
-}
-
-function device_running() {
-    var local_devices = shell.Exec("%comspec% /c adb devices").StdOut.ReadAll();
-    if(local_devices.match(/\w+\tdevice/)) {
-        WScript.Echo("Yes");
-        return true;
-    }
-    WScript.Echo("No");
-    return false;
-}
-function emulate() {
-    // don't run emulator if a device is plugged in or if emulator is already running
-    if(device_running()) {
-        //WScript.Echo("Device or Emulator already running!");
-        return;
-    }
-    var oExec = shell.Exec("%comspec% /c android.bat list avd");
-    var avd_list = [];
-    var avd_id = -10;
-    while(!oExec.StdOut.AtEndOfStream) {
-        var output = oExec.StdOut.ReadLine();
-        if(output.match(/Name: (.)*/)) {
-            avd_list.push(output.replace(/ *Name:\s/, ""));
-        }
-    }
-    // user has no AVDs
-    if(avd_list.length == 0) {
-        WScript.Echo("You don't have any Android Virtual Devices. Please create at least one AVD.");
-        WScript.Echo("android");
-        WScript.Quit(1);
-    }
-    // user has only one AVD so we launch that one
-    if(avd_list.length == 1) {
-
-        shell.Run("emulator -cpu-delay 0 -no-boot-anim -cache %Temp%\cache -avd "+avd_list[0]);
-    }
-
-    // user has more than one avd so we ask them to choose
-    if(avd_list.length > 1) {
-        while(!avd_list[avd_id]) {
-            WScript.Echo("Choose from one of the following Android Virtual Devices [0 to "+(avd_list.length - 1)+"]:")
-            for(i = 0, j = avd_list.length ; i < j ; i++) {
-                WScript.Echo((i)+") "+avd_list[i]);
-            }
-            WScript.StdOut.Write("> ");
-            avd_id = new Number(WScript.StdIn.ReadLine());
-        }
-
-        shell.Run("emulator -cpu-delay 0 -no-boot-anim -cache %Temp%\\cache -avd "+avd_list[avd_id], 0, false);
-    }
-}
-
-function clean() {
-    WScript.Echo("Cleaning project...");
-    exec("%comspec% /c ant.bat clean -f "+ROOT+"\\build.xml 2>&1");
-}
-
-function build() {
-    WScript.Echo("Building project...");
-    exec("%comspec% /c ant.bat debug -f "+ROOT+"\\build.xml 2>&1");
-}
-
-function install() {
-    WScript.Echo("Building/Installing project...");
-    exec("%comspec% /c ant.bat debug install -f "+ROOT+"\\build.xml 2>&1");
-}
-
-function log() {
-    shell.Run("%comspec% /c adb logcat");
-}
-
-function launch() {
-    WScript.Echo("Launching app...");
-    var launch_str=exec("%comspec% /c java -jar "+ROOT+"\\cordova\\appinfo.jar "+ROOT+"\\AndroidManifest.xml");
-    //WScript.Echo(launch_str);
-    exec("%comspec% /c adb shell am start -n "+launch_str+" 2>&1");
-}
-
-function run() {
-    var i=0;
-   clean();
-   emulate();
-   WScript.Stdout.Write('Waiting for device...');
-   while(!device_running() && i < 300) {
-        WScript.Stdout.Write('.');
-        WScript.sleep(1000);
-        i += 1;
-   }
-   if(i == 300) {
-       WScript.Stderr.WriteLine("device/emulator timeout!"); 
-   } else {
-       WScript.Stdout.WriteLine("connected!");
-   }
-   install();
-   launch();
-}
-var args = WScript.Arguments;
-if(args.count() != 1) {
-    WScript.StdErr.Write("An error has occured!\n");
-    WScript.Quit(1);
-}
-eval(args(0)+"()");

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/lib/cordova
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/cordova b/lib/cordova-android/bin/templates/cordova/lib/cordova
new file mode 100755
index 0000000..294df49
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/cordova
@@ -0,0 +1,386 @@
+#!/bin/bash
+#   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.
+
+PROJECT_PATH=$( cd "$( dirname "$0" )/../.." && pwd )
+
+function list_devices {
+    IFS=$'\n'
+    devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep -v 'emulator'`
+    device_list=($devices)
+    if [[ ${#device_list[@]} > 0 ]] ; then
+        for i in ${devices[@]}
+        do
+            # remove space and 'device'
+            echo ${i/[^a-zA-Z0-9._]device/}
+        done
+    else
+        echo "No devices found."
+        exit 2
+    fi
+}
+
+function list_started_emulators {
+    IFS=$'\n'
+    devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep 'emulator'`
+    emulator_list=($devices)
+    if [[ ${#emulator_list[@]} > 0 ]] ; then
+        for i in ${emulator_list[@]}
+        do
+            # remove space and 'device'
+            echo ${i/[^a-zA-Z0-9._]device/}
+        done
+    else
+        echo "No started emulators found, you can start an emulator by using the command"
+        echo " 'cordova/lib/start-emulator'"
+        exit 2
+    fi
+}
+
+function list_emulator_images {
+    emulator_images=`android list avds | grep "Name:" | cut -f 2 -d ":"`
+    emulator_list=($emulator_images)
+    if [[ ${#emulator_list[@]} > 0 ]] ; then
+        for i in ${emulator_list[@]}
+        do
+            echo ${i/[^a-zA-Z0-9._]/}
+        done
+    else
+        echo "No emulators found, if you would like to create an emulator follow the instructions"
+        echo " provided here : http://developer.android.com/tools/devices/index.html"
+        echo " Or run 'android create avd --name <name> --target <targetID>' in on the command line."
+        exit 2
+    fi
+}
+
+function start_emulator {
+    emulator_images=`android list avds | grep "Name:" | cut -f 2 -d ":"`
+    # if target emulator is provided
+    if [[ "$#" -eq 1 ]] ; then
+        # check that it exists
+        if [[ $emulator_images =~ $1 ]] ; then
+            #xterm -e emulator -avd $1 &
+            emulator -avd $1 1> /dev/null 2>&1 &
+        else
+            echo "Could not find the provided emulator, make sure the emulator exists"
+            echo " by checking 'cordova/lib/list-emulator-images'"
+            exit 2
+        fi
+    else
+        # start first emulator
+        emulator_list=($emulator_images)
+        if [[ ${#emulator_list[@]} > 0 ]] ; then
+            #xterm -e emulator -avd ${emulator_list[0]} &
+            emulator -avd ${emulator_list[0]/[^a-zA-Z0-9._]/} 1> /dev/null 2>&1 &
+        else
+            echo "No emulators found, if you would like to create an emulator follow the instructions"
+            echo " provided here : http://developer.android.com/tools/devices/index.html"
+            echo " Or run 'android create avd --name <name> --target <targetID>' in on the command line."
+            exit 2
+        fi
+    fi
+}
+
+function install_device {
+    IFS=$'\n'
+    devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep -v 'emulator'`
+    device_list=($devices)
+    if [[ ${#device_list[@]} > 0 ]] ; then
+        apks=`find $PROJECT_PATH/bin -type f -maxdepth 1 | egrep '\.apk$'`
+        apk_list=($apks)
+        if [[ ${#apk_list[@]} > 0 ]] ; then
+            local target
+            # handle target emulator
+            if [[ "$#" -eq 1 ]] ; then
+                # deploy to given target
+                target=${1/--target=/}
+            else
+                # delete trailing space and 'device' after device ID
+                target=${device_list[0]/[^a-zA-Z0-9._]device/}
+            fi
+            echo "Installing ${apk_list[0]} onto device $target..."
+            adb -s $target install -r ${apk_list[0]};
+            echo "Launching application..."
+            local launch_str=$(java -jar "$PROJECT_PATH"/cordova/appinfo.jar "$PROJECT_PATH"/AndroidManifest.xml)
+            adb -s $target shell am start -W -a android.intent.action.MAIN -n $launch_str
+        else
+            echo "Application package not found, could not install to device"
+            echo " make sure your application is built before deploying."
+            exit 2
+        fi
+    else
+        echo "No devices found to deploy to. Please make sure your device is connected"
+        echo " and you can view it using the 'cordova/lib/list-devices' command."
+        exit 2
+    fi
+}
+
+function install_emulator {
+    IFS=$'\n'
+    # check that there is an emulator to deploy to
+    emulator_string=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'emulator'`
+    emulator_list=($emulator_string)
+    if [[ ${#emulator_list[@]} > 0 ]] ; then
+        apks=`find $PROJECT_PATH/bin -type f -maxdepth 1 | egrep '\.apk$'`
+        apk_list=($apks)
+        if [[ ${#apk_list[@]} > 0 ]] ; then
+            local target
+            # handle target emulator
+            if [[ "$#" -eq 1 ]] ; then
+                # deploy to given target
+                target=${1/--target=/}
+            else
+                # delete trailing space and 'device' after emulator ID
+                target=${emulator_list[0]/[^a-zA-Z0-9._]device/}
+            fi
+            echo "Installing ${apk_list[0]} onto $target..."
+            adb -s $target install -r ${apk_list[0]};
+            echo "Launching application..."
+            local launch_str=$(java -jar "$PROJECT_PATH"/cordova/appinfo.jar "$PROJECT_PATH"/AndroidManifest.xml)
+            adb -s $target shell am start -W -a android.intent.action.MAIN -n $launch_str
+
+        else
+            echo "Application package not found, could not install to device"
+            echo " make sure your application is built before deploying."
+            exit 2
+        fi
+    else
+        echo "No emulators found to deploy to. Please make sure your emulator is started"
+        echo " and you can view it using the 'cordova/lib/list-started-emulators' command."
+        exit 2
+    fi
+}
+
+# cleans the project
+function clean {
+    echo "Cleaning project..."
+    ant clean
+}
+
+# has to be used independently and not in conjunction with other commands
+function log {
+    # filter out nativeGetEnabledTags spam from latest sdk bug.
+    adb logcat | grep -v nativeGetEnabledTags
+}
+
+
+function build {
+    if [[ "$#" -eq 1 ]] ; then
+        if [[ $1 == "--debug" ]] ; then
+            clean
+            ant debug -f "$PROJECT_PATH"/build.xml
+        elif [[ $1 == "--release" ]] ; then
+            clean
+            ant release -f "$PROJECT_PATH"/build.xml
+        elif [[ $1 == "--nobuild" ]] ; then
+            echo "Skipping build..."
+        else
+            echo "Error : Build command '$1' not recognized."
+            exit 2
+        fi
+    else
+        echo "Warning : [ --debug | --release | --nobuild ] not specified, defaulting to --debug"
+        clean
+        ant debug -f "$PROJECT_PATH"/build.xml
+    fi
+}
+
+
+function wait_for_emulator {
+    emulator_string=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep 'emulator'`
+    old_started=($emulator_string)
+    local new_started
+    local new_emulator_name
+    local i="0"
+    echo -n "Waiting for emulator..."
+    while [ $i -lt 300 ]
+    do
+        emulator_string=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep 'emulator'`
+        new_started=($emulator_string)
+        if [[ ${#new_started[@]} > ${#old_started[@]} && -z "$new_emulator_name" ]] ; then
+            # get the name of the started emulator
+            local count="0"
+            if [[ ${#old_started[@]} == 0 ]] ; then
+                new_emulator_name=${new_started[$count]/[^a-zA-Z0-9._]device/}
+            else
+                for count in {0...${#old_started[@]}}
+                do
+                    if [[ ! ${new_started[$count]} == ${old_started[$count]} ]] ; then
+                        new_emulator_name=${new_started[$count]/[^a-zA-Z0-9._]device/}
+                    fi
+                done
+                if [[ -z "$new_emulator_name" ]] ; then
+                    count=$[count+1]
+                    new_emulator_name=${new_started[$count]/[^a-zA-Z0-9._]device/}
+                fi
+            fi
+        elif [[ "$new_emulator_name" ]] ; then
+            boot_anim=`adb -s $new_emulator_name shell getprop init.svc.bootanim`
+            if [[ $boot_anim =~ "stopped" ]] ; then
+                break
+            else
+                sleep 1
+                i=$[i+1]
+                echo -n "."
+            fi
+        else
+            sleep 1
+            i=$[i+1]
+            echo -n "."
+        fi
+    done
+    # Device timeout: emulator has not started in time
+    if [ $i -eq 300 ]
+    then
+        echo "emulator timeout!"
+        exit 69
+    else
+        echo "connected!"
+    fi
+}
+
+function run {
+    IFS=$'\n'
+    if [[ "$#" -eq 2 ]] ; then
+        build $2
+        if [[ $1 == "--device" ]] ; then
+            install_device
+        elif [[ $1 == "--emulator" ]] ; then
+            install_emulator
+        elif [[ $1 =~ "--target=" ]]; then
+            install_device $1
+        else
+            echo "Error : '$1' is not recognized as an install option"
+        fi
+    elif [[ "$#" -eq 1 ]] ; then
+        if [[ $1 == "--debug" || $1 == "--release" || $1 == "--nobuild" ]] ; then
+            build $1
+        elif [[ $1 == "--device" ]] ; then
+            install_device
+        elif [[ $1 == "--emulator" ]] ; then
+            install_emulator
+        elif [[ $1 =~ "--target=" ]]; then
+            install_device $1
+        else
+            echo "Error : '$1' is not recognized as an install option"
+        fi
+    else
+        echo "Warning : [ --device | --emulate | --target=<targetID> ] not specified, using defaults."
+        build
+        devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep -v 'emulator'`
+        device_list=($devices)
+        emulator_string=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep 'emulator'`
+        emulator_list=($emulator_string)
+        if [[ ${#device_list[@]} > 0 ]] ; then
+            install_device
+        elif [[ ${#emulator_list[@]} > 0 ]] ; then
+            install_emulator
+        else
+            emulator_images=`android list avds | grep "Name:" | cut -f 2 -d ":"`
+            echo $emulator_images
+            emulator_image_list=($emulator_images)
+            if [[ ${#emulator_image_list[@]} > 0 ]] ; then
+                echo "Starting emulator : ${emulator_image_list[0]}" 
+                emulator -avd ${emulator_image_list[0]/[^.\w]/} 1> /dev/null 2>&1 &
+                wait_for_emulator
+                install_emulator
+            else
+                # TODO : look for emulator images and start one if it's availible
+                echo "Error : there are no availible devices or emulators to deploy to."
+                echo " create an emulator or connect your device to run this command."
+                echo "If you would like to create an emulator follow the instructions"
+                echo " provided here : http://developer.android.com/tools/devices/index.html"
+                echo " Or run 'android create avd --name <name> --target <targetID>' in on the command line."
+                exit 2
+            fi
+        fi
+    fi
+}
+
+# parse command line arguments
+
+if [[ $# > 3 ]] ; then 
+    echo "Error :  too many arguments."
+    exit 2
+elif [[ $# == 3 ]] ; then
+    if [[ $1 == "run" ]] ; then
+        run $2 $3
+    else
+        echo "Error : too many arguments for '$1'"
+        exit 2
+    fi
+elif [[ $# == 2 ]] ; then
+    if [[ $1 == "run" ]] ; then
+        if [[ $2 == "--emulator" || $2 == "--device" || $2 =~ "--target=" ]] ; then
+            run $2 ''
+        elif [[ $2 == "--debug" || $2 == "--release" || $2 == "--nobuild" ]] ; then
+            run '' $2
+        else 
+            echo "Error : '$2' is not recognized as a run option."
+            exit 2
+        fi
+    elif [[ $1 == "build" ]] ; then
+        build $2
+    elif [[ $1 == "start-emulator" ]] ; then
+        start_emulator $2
+    elif [[ $1 == "install-device" ]] ; then
+        if [[ $2 =~ "--target=" ]] ; then
+            install_device $2
+        else
+            echo "Error : '$2' is not recognized as an install option"
+            exit 2
+        fi
+    elif [[ $1 == "install-emulator" ]] ; then
+        if [[ $2 =~ "--target=" ]] ; then
+            install_emulator $2
+        else
+            echo "Error : '$2' is not recognized as an install option"
+            exit 2
+        fi
+    else
+        echo "Error : '$1' is not recognized as an option that takes arguments"
+        exit 2
+    fi
+elif [[ $# == 1 ]] ; then
+    if [[ $1 == "run" ]] ; then
+        run
+    elif [[ $1 == "build" ]]; then
+        build
+    elif [[ $1 == "clean" ]]; then
+        clean
+    elif [[ $1 == "log" ]]; then
+        log
+    elif [[ $1 == "list-devices" ]]; then
+        list_devices
+    elif [[ $1 == "list-emulator-images" ]]; then
+        list_emulator_images
+    elif [[ $1 == "list-started-emulators" ]]; then
+        list_started_emulators
+    elif [[ $1 == "install-device" ]]; then
+        install_device
+    elif [[ $1 == "install-emulator" ]]; then
+        install_emulator
+    elif [[ $1 == "start-emulator" ]]; then
+        start_emulator
+    else
+        echo "Error : '$1' is not recognized as a tooling command."
+        exit 2
+    fi
+else
+    echo "Error : No command recieved, exiting..."
+    exit 2
+fi
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/lib/cordova.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/cordova.js b/lib/cordova-android/bin/templates/cordova/lib/cordova.js
new file mode 100644
index 0000000..28f9b3e
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/cordova.js
@@ -0,0 +1,593 @@
+// 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 ROOT  = WScript.ScriptFullName.split('\\cordova\\lib\\cordova.js').join(''),
+    shell = WScript.CreateObject("WScript.Shell"),
+    fso   = WScript.CreateObject('Scripting.FileSystemObject');
+
+
+// log to stdout or stderr
+function Log(msg, error) {
+    if (error) {
+        WScript.StdErr.WriteLine(msg);
+    }
+    else {
+        WScript.StdOut.WriteLine(msg);
+    }
+} 
+
+// executes a commmand in the shell, returning stdout
+function exec(command) {
+    var oExec=shell.Exec(command);
+    var output = new String();
+    while (oExec.Status == 0) {
+        if (!oExec.StdOut.AtEndOfStream) {
+            var line = oExec.StdOut.ReadLine();
+            output += line;
+        }
+        WScript.sleep(100);
+    }
+    return output;
+}
+
+// executes a command in the shell, returns stdout or stderr if error
+function exec_out(command) {
+    var oExec=shell.Exec(command);
+    var output = new String();
+    while (oExec.Status == 0) {
+        if (!oExec.StdOut.AtEndOfStream) {
+            var line = oExec.StdOut.ReadLine();
+            // XXX: Change to verbose mode 
+            // WScript.StdOut.WriteLine(line);
+            output += line;
+        }
+        WScript.sleep(100);
+    }
+    //Check to make sure our scripts did not encounter an error
+    if (!oExec.StdErr.AtEndOfStream) {
+        var line = oExec.StdErr.ReadAll();
+        return {'error' : true, 'output' : line};
+    }
+    return {'error' : false, 'output' : output};
+}
+
+// executes a commmand in the shell and outputs stdout and fails on stderr
+function exec_verbose(command) {
+    //Log("Command: " + command);
+    var oShell=shell.Exec(command);
+    while (oShell.Status == 0) {
+        //Wait a little bit so we're not super looping
+        WScript.sleep(100);
+        //Print any stdout output from the script
+        if (!oShell.StdOut.AtEndOfStream) {
+            var line = oShell.StdOut.ReadLine();
+            Log(line);
+        }
+    }
+    //Check to make sure our scripts did not encounter an error
+    if (!oShell.StdErr.AtEndOfStream) {
+        var line = oShell.StdErr.ReadAll();
+        Log(line, true);
+        WScript.Quit(2);
+    }
+}
+
+function get_devices() {
+    var device_list = []
+    var local_devices = shell.Exec("%comspec% /c adb devices").StdOut.ReadAll();
+    if (local_devices.match(/\w+\tdevice/)) {
+        devices = local_devices.split('\r\n');
+        //format (ID DESCRIPTION)
+        for (i in devices) {
+            if (devices[i].match(/\w+\tdevice/) && !devices[i].match(/emulator/)) {
+                device_list.push(devices[i].replace(/\t/, ' '));
+            }
+        }
+    }
+    return device_list
+}
+
+function list_devices() {
+    var devices = get_devices();
+    if (devices.length > 0) {
+        for (i in devices) {
+            Log(devices[i]);
+        }
+    }
+    else {
+        Log('No devices found, if your device is connected and not showing,');
+        Log(' then try and install the drivers for your device.');
+        Log(' http://developer.android.com/tools/extras/oem-usb.html');
+    }
+
+}
+
+function get_emulator_images() {
+    // discription contains all data recieved squashed onto one line
+    var add_description = true;
+    var avd_list = [];
+    var local_emulators = shell.Exec("%comspec% /c android list avds").StdOut.ReadAll();
+    if (local_emulators.match(/Name\:/)) {
+        emulators = local_emulators.split('\n');
+        //format (ID DESCRIPTION)
+        var count = 0;
+        var output = '';
+        for (i in emulators) {
+            if (emulators[i].match(/Name\:/)) {
+                var emulator_name = emulators[i].replace(/\s*Name\:\s/, '') + ' ';
+                if (add_description) {
+                    count = 1;
+                    output += emulator_name
+                }
+                else {
+                    avd_list.push(emulator_name);
+                }
+            }
+            // add description if indicated (all data squeezed onto one line)
+            if (count > 0) {
+                var emulator_description = emulators[i].replace(/\s*/g, '');
+                if (count > 4) {
+                    avd_list.push(output + emulator_description);
+                    count = 0;
+                    output = '';
+                }
+                else {
+                    count++;
+                    output += emulator_description + ' '
+                }
+            }
+        }
+    }
+    return avd_list;
+}
+
+function list_emulator_images() {
+    var images = get_emulator_images();
+    if (images.length > 0) {
+        for(i in images) {
+            Log(images[i]);
+        }
+    }
+    else {
+        Log('No emulators found, if you would like to create an emulator follow the instructions');
+        Log(' provided here : http://developer.android.com/tools/devices/index.html');
+        Log(' Or run \'android create avd --name <name> --target <targetID>\' in on the command line.');
+    }
+}
+
+function get_started_emulators() {
+    var started_emulators = [];
+    var local_devices = shell.Exec("%comspec% /c adb devices").StdOut.ReadAll();
+    if (local_devices.match(/emulator/)) {
+        devices = local_devices.split('\r\n');
+        //format (ID DESCRIPTION)
+        for (i in devices) {
+            if (devices[i].match(/\w+\tdevice/) && devices[i].match(/emulator/)) {
+                started_emulators.push(devices[i].replace(/\t/, ' '));
+            }
+        }
+    }
+    return started_emulators
+}
+
+function list_started_emulators() {
+    var images = get_started_emulators();
+    if (images.length > 0) {
+        for(i in images) {
+            Log(images[i]);
+        }
+    }
+    else {
+        Log('No started emulators found, if you would like to start an emulator call \'list-emulator-images\'');
+        Log(' to get the name of an emulator and then start the emulator with \'start-emulator <Name>\'');
+    }
+}
+
+function start_emulator(name) {  
+    var emulators = get_emulator_images();
+    var started_emulators = get_started_emulators();
+    var num_started = started_emulators.length;
+    var emulator_name;
+    var started = false;
+    if (name) {
+        for (i in emulators) {
+            if (emulators[i].substr(0,name.length) == name) {
+                Log("Starting emulator : " + name);
+                shell.Run("%comspec% /c start cmd /c emulator -avd " + name);
+                //shell.Run("%comspec% /c start cmd /c emulator -cpu-delay 0 -no-boot-anim -cache %Temp%\cache -avd " + name);
+                started = true;
+            }
+        }
+    }
+    else {
+        if (emulators.length > 0 && started_emulators < 1) {
+            emulator_name = emulators[0].split(' ', 1)[0];
+            start_emulator(emulator_name);
+            return;
+        } else if (started_emulators.length > 0) {
+            Log("Emulator already started : " + started_emulators[0].split(' ', 1));
+            return;
+        } else {
+            Log("Error : unable to start emulator, ensure you have emulators availible by checking \'list-emulator-images\'", true);
+            WScript.Quit(2);
+        }
+    }
+    if (!started) {
+        Log("Error : unable to start emulator, ensure you have emulators availible by checking \'list-emulator-images\'", true);
+        WScript.Quit(2);
+    }
+    else { // wait for emulator to boot before returning
+        WScript.Stdout.Write('Booting up emulator..');
+        var boot_anim = null;
+        var emulator_ID = null;
+        var new_started = get_started_emulators();
+        var i = 0;
+        // use boot animation property to tell when boot is complete.
+        while ((boot_anim == null || !boot_anim.output.match(/stopped/)) && i < 100) {
+            if (new_started.length > started_emulators.length && emulator_ID == null) {
+                // find new emulator that was just started to get it's ID
+                for(var i = 0; i < new_started.length; i++) {
+                    if (new_started[i] != started_emulators[i]) {
+                        emulator_ID = new_started[i].split(' ', 1)[0];
+                        boot_anim = exec_out('%comspec% /c adb -s ' + emulator_ID + ' shell getprop init.svc.bootanim');
+                        break;
+                    }
+                }
+            }
+            else if (boot_anim == null) {
+                new_started = get_started_emulators(); 
+            }
+            else {
+                boot_anim = exec_out('%comspec% /c adb -s ' + emulator_ID + ' shell getprop init.svc.bootanim'); 
+            }
+            i++;
+            WScript.Stdout.Write('.');
+            WScript.Sleep(2000);
+        }
+        if (i < 100) {
+            Log('\nBoot Complete!');
+        } else {
+             Log('\nEmulator boot timed out. Failed to load emulator');
+             WScript.Quit(2);
+        }
+    }
+}
+
+function install_device(target) {
+    var devices = get_devices();
+    var use_target = false;
+    if (devices.length < 1) {
+        Log("Error : No devices found to install to, make sure there are devices", true);
+        Log(" availible by checking \'<project_dir>\\cordova\\lib\\list-devices\'", true);
+        WScript.Quit(2);
+    }
+    if (target) {
+        var exists = false;
+        for (i in devices) {
+            if (devices[i].substr(0,target.length) == target)
+            {
+                exists = true;
+                break;
+            }
+        }
+        if (!exists) {
+            Log("Error : Unable to find target " + target, true);
+            Log("Please ensure the target exists by checking \'<project>\\cordova\\lib\\list-devices'");
+            WScript.Quit(2);
+        }
+        use_target = true;
+    }
+    // check if file .apk has been created
+    if (fso.FolderExists(ROOT + '\\bin')) {
+        var path_to_apk;
+        var out_folder = fso.GetFolder(ROOT + '\\bin');
+        var out_files = new Enumerator(out_folder.Files);
+        for (;!out_files.atEnd(); out_files.moveNext()) {
+            var path = out_files.item() + '';
+            if (fso.GetExtensionName(path) == 'apk' && !path.match(/unaligned/)) {
+                path_to_apk = out_files.item();
+                break;
+            }
+        }
+        if (path_to_apk) {
+            var launch_name = exec_out("%comspec% /c java -jar "+ROOT+"\\cordova\\appinfo.jar "+ROOT+"\\AndroidManifest.xml");
+            if (launch_name.error) {
+                Log("Failed to get application name from appinfo.jar + AndroidManifest : ", true);
+                Log("Output : " + launch_name.output, true);
+                WScript.Quit(2);
+            }
+            // install on device (-d)
+            Log("Installing app on device...");
+            var cmd;
+            if (use_target) {
+                cmd = '%comspec% /c adb -s ' + target + ' install -r ' + path_to_apk;
+            } else {
+                cmd = '%comspec% /c adb -s ' + devices[0].split(' ', 1)[0] + ' install -r ' + path_to_apk;
+            }
+            var install = exec_out(cmd);
+            if ( install.error && install.output.match(/Failure/)) {
+                Log("Error : Could not install apk to device : ", true);
+                Log(install.output, true);
+                WScript.Quit(2);
+            }
+            else {
+                Log(install.output);
+            }
+            // run on device
+            Log("Launching application...");
+            cmd;
+            if (use_target) {
+                cmd = '%comspec% /c adb -s ' + target + ' shell am start -W -a android.intent.action.MAIN -n ' + launch_name.output;
+            } else {
+                cmd = '%comspec% /c adb -s ' + devices[0].split(' ', 1)[0] + ' shell am start -W -a android.intent.action.MAIN -n ' + launch_name.output;
+            }
+            exec_verbose(cmd);
+        }
+        else {
+            Log('Failed to find apk, make sure you project is built and there is an ', true);
+            Log(' apk in <project>\\bin\\.  To build your project use \'<project>\\cordova\\build\'', true);
+            WScript.Quit(2);
+        }
+    }
+}
+
+function install_emulator(target) {
+    var emulators = get_started_emulators();
+    var use_target = false;
+    if (emulators.length < 1) {
+        Log("Error : No emulators found to install to, make sure there are emulators", true);
+        Log(" availible by checking \'<project_dir>\\cordova\\lib\\list-started-emulators\'", true);
+        WScript.Quit(2);
+    }
+    if (target) {
+        var exists = false;
+        for (i in emulators) {
+            if (emulators[i].substr(0,target.length) == target)
+            {
+                exists = true;
+                break;
+            }
+        }
+        if (!exists) {
+            Log("Error : Unable to find target " + target, true);
+            Log("Please ensure the target exists by checking \'<project>\\cordova\\lib\\list-started-emulators'")
+        }
+        use_target = true;
+    } else {
+        target = emulators[0].split(' ', 1)[0];
+        Log("Deploying to emulator : " + target);
+    }
+    // check if file .apk has been created
+    if (fso.FolderExists(ROOT + '\\bin')) {
+        var path_to_apk;
+        var out_folder = fso.GetFolder(ROOT + '\\bin');
+        var out_files = new Enumerator(out_folder.Files);
+        for (;!out_files.atEnd(); out_files.moveNext()) {
+            var path = out_files.item() + '';
+            if (fso.GetExtensionName(path) == 'apk' && !path.match(/unaligned/)) {
+                path_to_apk = out_files.item();
+                break;
+            }
+        }
+        if (path_to_apk) {
+            var launch_name = exec_out("%comspec% /c java -jar "+ROOT+"\\cordova\\appinfo.jar "+ROOT+"\\AndroidManifest.xml");
+            if (launch_name.error) {
+                Log("Failed to get application name from appinfo.jar + AndroidManifest : ", true);
+                Log("Output : " + launch_name.output, true);
+                WScript.Quit(2);
+            }
+            // install on emulator (-e)
+            Log("Installing app on emulator...");
+            var cmd = '%comspec% /c adb -s ' + target + ' install -r ' + path_to_apk;
+            var install = exec_out(cmd);
+            if ( install.error && install.output.match(/Failure/)) {
+                Log("Error : Could not install apk to emulator : ", true);
+                Log(install.output, true);
+                WScript.Quit(2);
+            }
+            else {
+                Log(install.output);
+            }
+            // run on emulator
+            Log("Launching application...");
+            cmd;
+            if (use_target) {
+                cmd = '%comspec% /c adb -s ' + target + ' shell am start -W -a android.intent.action.MAIN -n ' + launch_name.output;
+            } else {
+                cmd = '%comspec% /c adb -s ' + emulators[0].split(' ', 1)[0] + ' shell am start -W -a android.intent.action.MAIN -n ' + launch_name.output
+            }
+            exec_verbose(cmd);
+        }
+        else {
+            Log('Failed to find apk, make sure you project is built and there is an ', true);
+            Log(' apk in <project>\\bin\\.  To build your project use \'<project>\\cordova\\build\'', true);
+            WScript.Quit(2);
+        }
+    }
+    else {
+        Log('Failed to find apk, make sure you project is built and there is an ', true);
+        Log(' apk in <project>\\bin\\.  To build your project use \'<project>\\cordova\\build\'', true);
+        WScript.Quit(2);
+    }
+}
+
+function clean() {
+    Log("Cleaning project...");
+    exec("%comspec% /c ant.bat clean -f "+ROOT+"\\build.xml 2>&1");
+}
+
+function build(build_type) {
+    if (build_type) {
+        switch (build_type) {
+            case "--debug" :
+                clean();
+                Log("Building project...");
+                exec_verbose("%comspec% /c ant.bat debug -f "+ROOT+"\\build.xml 2>&1");
+                break;
+            case "--release" :
+                clean();
+                Log("Building project...");
+                exec_verbose("%comspec% /c ant.bat release -f "+ROOT+"\\build.xml 2>&1");
+                break;
+            case "--nobuild" :
+                Log("Skipping build process.");
+                break;
+            default :
+                Log("Build option not recognized: " + build_type, true);
+                WScript.Quit(2);
+                break;
+        }
+    }
+    else {
+        Log("WARNING: [ --debug | --release | --nobuild ] not specified, defaulting to --debug.");
+        exec_verbose("%comspec% /c ant.bat debug -f "+ROOT+"\\build.xml 2>&1");
+    }
+}
+
+function log() {
+    // filter out nativeGetEnabledTags spam from latest sdk bug.
+    shell.Run("%comspec% /c adb logcat | grep -v nativeGetEnabledTags");
+}
+
+function run(target, build_type) {
+    var use_target = false;
+    if (!target) {
+        Log("WARNING: [ --target=<ID> | --emulator | --device ] not specified, using defaults");
+    }
+    // build application
+    build(build_type);
+    // attempt to deploy to connected device 
+    var devices = get_devices();
+    if (devices.length > 0 || target == "--device") {
+        if (target) {
+            if (target.substr(0,9) == "--target=") {
+                install_device(target.split('--target=').join(''))
+            } else if (target == "--device") {
+                install_device();
+            } else {
+                Log("Did not regognize " + target + " as a run option.", true);
+                WScript.Quit(2);
+            }
+        }
+        else {
+            Log("WARNING: [ --target=<ID> | --emulator | --device ] not specified, using defaults");
+            install_device();
+        }
+    }
+    else {
+        var emulators = get_started_emulators();
+        if (emulators.length > 0) {
+            install_emulator();
+        }
+        else {
+            var emulator_images = get_emulator_images();
+            if (emulator_images.length < 1) {
+                Log('No emulators found, if you would like to create an emulator follow the instructions', true);
+                Log(' provided here : http://developer.android.com/tools/devices/index.html', true);
+                Log(' Or run \'android create avd --name <name> --target <targetID>\' in on the command line.', true);
+                WScript.Quit(2);
+            }
+            start_emulator(emulator_images[0].split(' ')[0]);
+            emulators = get_started_emulators();
+            if (emulators.length > 0) {
+                install_emulator();
+            }
+            else {
+                Log("Error : emulator failed to start.", true);
+                WScript.Quit(2);
+            }
+        }
+    }
+}
+
+var args = WScript.Arguments;
+if (args.count() == 0) {
+    Log("Error: no args provided.");
+    WScript.Quit(2);
+}
+else {
+    if (args(0) == "build") {
+        if (args.Count() > 1) {
+            build(args(1))
+        } else {
+            build();
+        }
+    } else if (args(0) == "clean") {
+        clean();
+    } else if (args(0) == "list-devices") {
+        list_devices();
+    } else if (args(0) == "list-emulator-images") {
+        list_emulator_images();
+    } else if (args(0) == "list-started-emulators") {
+        list_started_emulators();
+    } else if (args(0) == "start-emulator") {
+        if (args.Count() > 1) {
+            start_emulator(args(1))
+        } else {
+            start_emulator();
+        }
+    } else if (args(0) == "log") {
+        log();
+    } else if (args(0) == "install-emulator") {
+        if (args.Count() == 2) {
+            if (args(1).substr(0,9) == "--target=") {
+                install_emulator(args(1).split('--target=').join(''));
+            } else {
+                Log('Error: \"' + args(1) + '\" is not recognized as an install option', true);
+                WScript.Quit(2);
+            }
+        } else {
+            install_emulator();
+        }
+    } else if (args(0) == "install-device") {
+        if (args.Count() == 2) {
+            if (args(1).substr(0,9) == "--target=") {
+                install_device(args(1).split('--target=').join(''));
+            } else {
+                Log('Error: \"' + args(1) + '\" is not recognized as an install option', true);
+                WScript.Quit(2);
+            }
+        } else {
+            install_device();
+        }
+    } else if (args(0) == "run") {
+        if (args.Count() == 3) {
+            run(args(1), args(2));
+        }
+        else if (args.Count() == 2) {
+            if (args(1).substr(0,9) == "--target=" ||
+               args(1) == "--emulator" ||
+               args(1) == "--device") {
+                run(args(1));
+            } else if (args(1) == "--debug" ||
+                       args(1) == "--release" ||
+                       args(1) == "--nobuild") {
+                run(null, args(1))
+            } else {
+                Log('Error: \"' + args(1) + '\" is not recognized as a run option', true);
+                WScript.Quit(2);
+            }
+        }
+        else {
+            run();
+        }
+    } else {
+        Log('Error: \"' + args(0) + '\" is not recognized as a tooling command', true);
+        WScript.Quit(2);
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/lib/install-device
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/install-device b/lib/cordova-android/bin/templates/cordova/lib/install-device
new file mode 100755
index 0000000..604b5ae
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/install-device
@@ -0,0 +1,23 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
+
+bash "$CORDOVA_LIB_PATH"/cordova install-device "$@"
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/lib/install-device.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/install-device.bat b/lib/cordova-android/bin/templates/cordova/lib/install-device.bat
new file mode 100644
index 0000000..52d9775
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/install-device.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%cordova.js (
+    cscript "%full_path%cordova.js" install-device %* //nologo
+) ELSE (
+    ECHO. 
+    ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/lib/install-emulator
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/install-emulator b/lib/cordova-android/bin/templates/cordova/lib/install-emulator
new file mode 100755
index 0000000..105e2ee
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/install-emulator
@@ -0,0 +1,23 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
+
+bash "$CORDOVA_LIB_PATH"/cordova install-emulator "$@"
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/lib/install-emulator.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/install-emulator.bat b/lib/cordova-android/bin/templates/cordova/lib/install-emulator.bat
new file mode 100644
index 0000000..d11a7be
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/install-emulator.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%cordova.js (
+    cscript "%full_path%cordova.js" install-emulator %* //nologo
+) ELSE (
+    ECHO. 
+    ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/lib/list-devices
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-devices b/lib/cordova-android/bin/templates/cordova/lib/list-devices
new file mode 100755
index 0000000..7a5b2f5
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/list-devices
@@ -0,0 +1,23 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
+
+bash "$CORDOVA_LIB_PATH"/cordova list-devices
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/lib/list-devices.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-devices.bat b/lib/cordova-android/bin/templates/cordova/lib/list-devices.bat
new file mode 100644
index 0000000..c146f10
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/list-devices.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%cordova.js (
+    cscript "%full_path%cordova.js" list-devices //nologo
+) ELSE (
+    ECHO. 
+    ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images b/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images
new file mode 100755
index 0000000..db8e563
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images
@@ -0,0 +1,23 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
+
+bash "$CORDOVA_LIB_PATH"/cordova list-emulator-images
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images.bat b/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images.bat
new file mode 100644
index 0000000..172520b
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%cordova.js (
+    cscript "%full_path%cordova.js" list-emulator-images //nologo
+) ELSE (
+    ECHO. 
+    ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file


[14/43] git commit: Chaning plugman.js to main.js as run target

Posted by an...@apache.org.
Chaning plugman.js to main.js as run target


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

Branch: refs/heads/master
Commit: b6be347260bb18fa0046c291802ef77dbc6aa8b1
Parents: 548ae52
Author: Michal Mocny <mm...@gmail.com>
Authored: Mon Apr 22 14:01:18 2013 -0400
Committer: Michal Mocny <mm...@gmail.com>
Committed: Mon Apr 22 14:01:18 2013 -0400

----------------------------------------------------------------------
 src/platform.js |    2 +-
 src/plugin.js   |    2 +-
 src/prepare.js  |    2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b6be3472/src/platform.js
----------------------------------------------------------------------
diff --git a/src/platform.js b/src/platform.js
index 1862f72..587e687 100644
--- a/src/platform.js
+++ b/src/platform.js
@@ -107,7 +107,7 @@ module.exports = function platform(command, targets, callback) {
                                 var pluginsDir = path.join(projectRoot, 'plugins');
                                 var plugins = fs.readdirSync(pluginsDir);
                                 plugins && plugins.forEach(function(plugin) {
-                                    var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'plugman.js');
+                                    var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'main.js');
                                     var cmd = util.format('"%s" --platform "%s" --project "%s" --plugin "%s" --plugins_dir "%s"', cli, target, output, path.basename(plugin), pluginsDir);
                                     var result = shell.exec(cmd, { silent: true });
                                     if (result.code > 0) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b6be3472/src/plugin.js
----------------------------------------------------------------------
diff --git a/src/plugin.js b/src/plugin.js
index c2fdc02..55ccf48 100644
--- a/src/plugin.js
+++ b/src/plugin.js
@@ -73,7 +73,7 @@ module.exports = function plugin(command, targets, callback) {
         case 'add':
             targets.forEach(function(target, index) {
                 hooks.fire('before_plugin_add');
-                var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'plugman.js');
+                var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'main.js');
                 var pluginsDir = path.join(projectRoot, 'plugins');
 
                 if (target[target.length - 1] == path.sep) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/b6be3472/src/prepare.js
----------------------------------------------------------------------
diff --git a/src/prepare.js b/src/prepare.js
index 7b30c29..0b6d060 100644
--- a/src/prepare.js
+++ b/src/prepare.js
@@ -69,7 +69,7 @@ module.exports = function prepare(platforms, callback) {
         if (callback) callback();
     });
 
-    var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'plugman.js');
+    var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'main.js');
 
     // Iterate over each added platform
     platforms.forEach(function(platform) {


[18/43] git commit: CB-2811: shell and module-level hooks should receive project root as parameter.

Posted by an...@apache.org.
CB-2811: shell and module-level hooks should receive project root as parameter.


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

Branch: refs/heads/master
Commit: 72e72659fba59ccb38f93b2760922b2a3cebffc8
Parents: 1ed1ee2
Author: Fil Maj <ma...@gmail.com>
Authored: Thu Mar 28 13:03:53 2013 -0700
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu May 9 14:26:05 2013 -0700

----------------------------------------------------------------------
 README.md           |    6 +++++-
 cordova.js          |   15 ++++++++++++---
 spec/hooker.spec.js |   45 ++++++++++++++++++++++++++++++++++++++++++---
 src/events.js       |    1 -
 src/hooker.js       |    5 +++--
 5 files changed, 62 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/72e72659/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 291c037..db232ce 100644
--- a/README.md
+++ b/README.md
@@ -110,7 +110,9 @@ Any added plugins will be extracted or copied into this directory.
 
 # Hooks
 
-Projects created by cordova-cli have `before` and `after` hooks for each [project command](#project_commands). There are two types of hooks: project-specific ones and module-level ones.
+Projects created by cordova-cli have `before` and `after` hooks for each [project command](#project_commands).
+
+There are two types of hooks: project-specific ones and module-level ones. Both of these types of hooks receive the project root folder as a parameter.
 
 ## Project-specific Hooks
 
@@ -124,6 +126,8 @@ These are located under the `.cordova/hooks` directory in the root of your cordo
 
 If you are using cordova-cli as a module within a larger node application, you can also use the standard `EventEmitter` methods to attach to the events. The events include `before_build`, `before_compile`, `before_docs`, `before_emulate`, `before_platform_add`, `before_platform_ls`, `before_platform_rm`, `before_plugin_add`, `before_plugin_ls`, `before_plugin_rm` and `before_prepare`. Additionally, there are `after_` flavours of all the above events.
 
+Once you `require('cordova')` in your node project, you will have the usual `EventEmitter` methods available (`on`, `off` or `removeListener`, and `emit` or `trigger`).
+
 # Examples
 
 ## Creating a new cordova project

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/72e72659/cordova.js
----------------------------------------------------------------------
diff --git a/cordova.js b/cordova.js
index b8f5328..73d3a64 100755
--- a/cordova.js
+++ b/cordova.js
@@ -25,6 +25,14 @@ var cordova_events = require('./src/events'),
     fs             = require('fs'),
     compile        = require('./src/compile');
 
+var off = function() {
+    cordova_events.removeListener.apply(cordova_events, arguments);
+};
+
+var emit = function() {
+    cordova_events.emit.apply(cordova_events, arguments);
+};
+
 module.exports = {
     help:      require('./src/help'),
     create:    require('./src/create'),
@@ -40,9 +48,10 @@ module.exports = {
     on:        function() {
         cordova_events.on.apply(cordova_events, arguments);
     },
-    emit:      function() {
-        cordova_events.emit.apply(cordova_events, arguments);
-    },
+    off:       off,
+    removeListener:off,
+    emit:      emit,
+    trigger:   emit,
     build:     function() {
         var projectRoot = util.isCordova(process.cwd());
         if (!projectRoot) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/72e72659/spec/hooker.spec.js
----------------------------------------------------------------------
diff --git a/spec/hooker.spec.js b/spec/hooker.spec.js
index 1090267..4a0ca7d 100644
--- a/spec/hooker.spec.js
+++ b/spec/hooker.spec.js
@@ -1,4 +1,3 @@
-
 /**
     Licensed to the Apache Software Foundation (ASF) under one
     or more contributor license agreements.  See the NOTICE file
@@ -90,8 +89,48 @@ describe('hooker', function() {
                     returnValue = h.fire('before_build');
                 }).not.toThrow();
                 expect(returnValue).toBe(true);
-                expect(s.calls[0].args[0]).toMatch(/0.sh$/);
-                expect(s.calls[1].args[0]).toMatch(/1.sh$/);
+                expect(s.calls[0].args[0]).toMatch(/0.sh/);
+                expect(s.calls[1].args[0]).toMatch(/1.sh/);
+            });
+            it('should pass the project root folder as parameter into the project-level hooks', function() {
+                var hook = path.join(tempDir, '.cordova', 'hooks', 'before_build');
+                shell.cp(path.join(hooks, 'test', '0.sh'), path.join(hook, '.'));
+                fs.readdirSync(hook).forEach(function(script) {
+                    fs.chmodSync(path.join(hook, script), '754');
+                });
+                var returnValue;
+                var s = spyOn(shell, 'exec').andReturn({code:0});
+                expect(function() {
+                    returnValue = h.fire('before_build');
+                }).not.toThrow();
+                expect(returnValue).toBe(true);
+                var paramRegex = new RegExp('0.sh "'+tempDir+'"$');
+                expect(s.calls[0].args[0]).toMatch(paramRegex);
+            });
+            describe('module-level hooks', function() {
+                var handler = jasmine.createSpy();
+                var test_event = 'before_build';
+                afterEach(function() {
+                    cordova.off(test_event, handler);
+                    handler.reset();
+                });
+
+                it('should fire handlers using cordova.on', function() {
+                    cordova.on(test_event, handler);
+                    h.fire(test_event);
+                    expect(handler).toHaveBeenCalled();
+                });
+                it('should pass the project root folder as parameter into the module-level handlers', function() {
+                    cordova.on(test_event, handler);
+                    h.fire('before_build');
+                    expect(handler).toHaveBeenCalledWith(tempDir);
+                });
+                it('should be able to stop listening to events using cordova.off', function() {
+                    cordova.on(test_event, handler);
+                    cordova.off(test_event, handler);
+                    h.fire('before_build');
+                    expect(handler).not.toHaveBeenCalled();
+                });
             });
         });
     });

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/72e72659/src/events.js
----------------------------------------------------------------------
diff --git a/src/events.js b/src/events.js
index 625b7e8..be40fec 100644
--- a/src/events.js
+++ b/src/events.js
@@ -1,4 +1,3 @@
-
 /**
     Licensed to the Apache Software Foundation (ASF) under one
     or more contributor license agreements.  See the NOTICE file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/72e72659/src/hooker.js
----------------------------------------------------------------------
diff --git a/src/hooker.js b/src/hooker.js
index 8903fdb..5a0eb3c 100644
--- a/src/hooker.js
+++ b/src/hooker.js
@@ -35,14 +35,15 @@ module.exports.prototype = {
         if (!(fs.existsSync(dir))) return true; // hooks directory got axed post-create; ignore.
 
         // Fire JS hook/event
-        events.emit(hook);
+        events.emit(hook, this.root);
 
         // Fire script-based hooks
         var contents = fs.readdirSync(dir);
+        var self = this;
         contents.forEach(function(script) {
             var fullpath = path.join(dir, script);
             if (fs.statSync(fullpath).isDirectory()) return; // skip directories if they're in there.
-            var status = shell.exec(fullpath);
+            var status = shell.exec(fullpath + ' "' + self.root + '"');
             if (status.code !== 0) throw new Error('Script "' + path.basename(script) + '"' + 'in the ' + hook + ' hook exited with non-zero status code. Aborting.');
         });
         return true;


[02/43] git commit: Make cordova plugin add rely on plugman

Posted by an...@apache.org.
Make cordova plugin add rely on plugman


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

Branch: refs/heads/master
Commit: 76ed29cc330d2fe79bd092c106b0ab6b31cdc626
Parents: bdd9210
Author: Braden Shepherdson <br...@gmail.com>
Authored: Mon Mar 25 17:33:45 2013 -0400
Committer: Braden Shepherdson <br...@gmail.com>
Committed: Mon Mar 25 17:33:45 2013 -0400

----------------------------------------------------------------------
 src/plugin.js  |   44 ++++----------------------------------------
 src/prepare.js |    1 -
 2 files changed, 4 insertions(+), 41 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/76ed29cc/src/plugin.js
----------------------------------------------------------------------
diff --git a/src/plugin.js b/src/plugin.js
index 93e90d8..b323429 100644
--- a/src/plugin.js
+++ b/src/plugin.js
@@ -70,52 +70,16 @@ module.exports = function plugin(command, targets, callback) {
             } else return 'No plugins added. Use `cordova plugin add <plugin>`.';
             break;
         case 'add':
-            if (platforms.length === 0) {
-                throw new Error('You need at least one platform added to your app. Use `cordova platform add <platform>`.');
-            }
             targets.forEach(function(target, index) {
-                var pluginContents = ls(target);
-                var targetName = names[index];
-                // Check if we already have the plugin.
-                // TODO edge case: if a new platform is added, then you want
-                // to re-add the plugin to the new platform.
-                if (plugins.indexOf(targetName) > -1) {
-                    throw new Error('Plugin "' + targetName + '" already added to project.');
-                }
-                // Check if the plugin has a plugin.xml in the root of the
-                // specified dir.
-                if (pluginContents.indexOf('plugin.xml') == -1) {
-                    throw new Error('Plugin "' + targetName + '" does not have a plugin.xml in the root. Plugin must support the Cordova Plugin Specification: https://github.com/alunny/cordova-plugin-spec');
-                }
-
-                // Check if there is at least one match between plugin
-                // supported platforms and app platforms
-                var pluginXml = new plugin_parser(path.join(target, 'plugin.xml'));
-                var intersection = pluginXml.platforms.filter(function(e) {
-                    if (platforms.indexOf(e) == -1) return false;
-                    else return true;
-                });
-                if (intersection.length === 0) {
-                    throw new Error('Plugin "' + targetName + '" does not support any of your application\'s platforms. Plugin platforms: ' + pluginXml.platforms.join(', ') + '; your application\'s platforms: ' + platforms.join(', '));
-                }
-
                 hooks.fire('before_plugin_add');
-
                 var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'plugman.js');
-
-                // Iterate over all matchin app-plugin platforms in the project and install the
-                // plugin.
-                intersection.forEach(function(platform) {
-                    var cmd = util.format('%s --platform %s --project "%s" --plugin "%s"', cli, platform, path.join(projectRoot, 'platforms', platform), target);
+                // Iterate over all platforms in the project and install the plugin.
+                platforms.forEach(function(platform) {
+                    var cmd = util.format('%s --platform %s --project "%s" --plugin "%s" --plugins_dir "%s"', cli, platform, path.join(projectRoot, 'platforms', platform), target, path.join(projectRoot, 'plugins'));
                     var plugin_cli = shell.exec(cmd, {silent:true});
-                    if (plugin_cli.code > 0) throw new Error('An error occured during plugin installation for ' + platform + '. ' + plugin_cli.output);
+                    if (plugin_cli.code > 0) throw new Error('An error occured during plugin installation for ' + platform + ': ' + plugin_cli.output);
                 });
 
-                // Finally copy the plugin into the project
-                var targetPath = path.join(pluginPath, targetName);
-                shell.mkdir('-p', targetPath);
-                shell.cp('-r', path.join(target, '*'), targetPath);
-
                 hooks.fire('after_plugin_add');
             });
             if (callback) callback();

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/76ed29cc/src/prepare.js
----------------------------------------------------------------------
diff --git a/src/prepare.js b/src/prepare.js
index 0d47acd..f5164eb 100644
--- a/src/prepare.js
+++ b/src/prepare.js
@@ -78,7 +78,6 @@ module.exports = function prepare(platforms, callback) {
         parser.update_project(cfg, function() {
             // Call plugman --prepare for each platform.
             var cmd = util.format('%s --prepare --platform "%s" --project "%s" --www "%s" --plugins_dir "%s"', cli, platform, platformPath, parser.www_dir(), path.join(projectRoot, 'plugins'));
-            console.log(cmd);
             var plugman_call = shell.exec(cmd, {silent:true});
             if (plugman_call.code > 0) throw new Error('An error occurred during plugman --prepare for ' + platform + ': ' + plugman_call.output);
 


[09/43] Move www/ and merges/ into app/.

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/spec/lib/jasmine-1.2.0/jasmine.js
----------------------------------------------------------------------
diff --git a/templates/app/www/spec/lib/jasmine-1.2.0/jasmine.js b/templates/app/www/spec/lib/jasmine-1.2.0/jasmine.js
new file mode 100644
index 0000000..03bf89a
--- /dev/null
+++ b/templates/app/www/spec/lib/jasmine-1.2.0/jasmine.js
@@ -0,0 +1,2529 @@
+var isCommonJS = typeof window == "undefined";
+
+/**
+ * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
+ *
+ * @namespace
+ */
+var jasmine = {};
+if (isCommonJS) exports.jasmine = jasmine;
+/**
+ * @private
+ */
+jasmine.unimplementedMethod_ = function() {
+  throw new Error("unimplemented method");
+};
+
+/**
+ * Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
+ * a plain old variable and may be redefined by somebody else.
+ *
+ * @private
+ */
+jasmine.undefined = jasmine.___undefined___;
+
+/**
+ * Show diagnostic messages in the console if set to true
+ *
+ */
+jasmine.VERBOSE = false;
+
+/**
+ * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
+ *
+ */
+jasmine.DEFAULT_UPDATE_INTERVAL = 250;
+
+/**
+ * Default timeout interval in milliseconds for waitsFor() blocks.
+ */
+jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
+
+jasmine.getGlobal = function() {
+  function getGlobal() {
+    return this;
+  }
+
+  return getGlobal();
+};
+
+/**
+ * Allows for bound functions to be compared.  Internal use only.
+ *
+ * @ignore
+ * @private
+ * @param base {Object} bound 'this' for the function
+ * @param name {Function} function to find
+ */
+jasmine.bindOriginal_ = function(base, name) {
+  var original = base[name];
+  if (original.apply) {
+    return function() {
+      return original.apply(base, arguments);
+    };
+  } else {
+    // IE support
+    return jasmine.getGlobal()[name];
+  }
+};
+
+jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
+jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
+jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
+jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
+
+jasmine.MessageResult = function(values) {
+  this.type = 'log';
+  this.values = values;
+  this.trace = new Error(); // todo: test better
+};
+
+jasmine.MessageResult.prototype.toString = function() {
+  var text = "";
+  for (var i = 0; i < this.values.length; i++) {
+    if (i > 0) text += " ";
+    if (jasmine.isString_(this.values[i])) {
+      text += this.values[i];
+    } else {
+      text += jasmine.pp(this.values[i]);
+    }
+  }
+  return text;
+};
+
+jasmine.ExpectationResult = function(params) {
+  this.type = 'expect';
+  this.matcherName = params.matcherName;
+  this.passed_ = params.passed;
+  this.expected = params.expected;
+  this.actual = params.actual;
+  this.message = this.passed_ ? 'Passed.' : params.message;
+
+  var trace = (params.trace || new Error(this.message));
+  this.trace = this.passed_ ? '' : trace;
+};
+
+jasmine.ExpectationResult.prototype.toString = function () {
+  return this.message;
+};
+
+jasmine.ExpectationResult.prototype.passed = function () {
+  return this.passed_;
+};
+
+/**
+ * Getter for the Jasmine environment. Ensures one gets created
+ */
+jasmine.getEnv = function() {
+  var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
+  return env;
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isArray_ = function(value) {
+  return jasmine.isA_("Array", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isString_ = function(value) {
+  return jasmine.isA_("String", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isNumber_ = function(value) {
+  return jasmine.isA_("Number", value);
+};
+
+/**
+ * @ignore
+ * @private
+ * @param {String} typeName
+ * @param value
+ * @returns {Boolean}
+ */
+jasmine.isA_ = function(typeName, value) {
+  return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
+};
+
+/**
+ * Pretty printer for expecations.  Takes any object and turns it into a human-readable string.
+ *
+ * @param value {Object} an object to be outputted
+ * @returns {String}
+ */
+jasmine.pp = function(value) {
+  var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
+  stringPrettyPrinter.format(value);
+  return stringPrettyPrinter.string;
+};
+
+/**
+ * Returns true if the object is a DOM Node.
+ *
+ * @param {Object} obj object to check
+ * @returns {Boolean}
+ */
+jasmine.isDomNode = function(obj) {
+  return obj.nodeType > 0;
+};
+
+/**
+ * Returns a matchable 'generic' object of the class type.  For use in expecations of type when values don't matter.
+ *
+ * @example
+ * // don't care about which function is passed in, as long as it's a function
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
+ *
+ * @param {Class} clazz
+ * @returns matchable object of the type clazz
+ */
+jasmine.any = function(clazz) {
+  return new jasmine.Matchers.Any(clazz);
+};
+
+/**
+ * Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
+ * attributes on the object.
+ *
+ * @example
+ * // don't care about any other attributes than foo.
+ * expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
+ *
+ * @param sample {Object} sample
+ * @returns matchable object for the sample
+ */
+jasmine.objectContaining = function (sample) {
+    return new jasmine.Matchers.ObjectContaining(sample);
+};
+
+/**
+ * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
+ *
+ * Spies should be created in test setup, before expectations.  They can then be checked, using the standard Jasmine
+ * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
+ *
+ * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
+ *
+ * Spies are torn down at the end of every spec.
+ *
+ * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
+ *
+ * @example
+ * // a stub
+ * var myStub = jasmine.createSpy('myStub');  // can be used anywhere
+ *
+ * // spy example
+ * var foo = {
+ *   not: function(bool) { return !bool; }
+ * }
+ *
+ * // actual foo.not will not be called, execution stops
+ * spyOn(foo, 'not');
+
+ // foo.not spied upon, execution will continue to implementation
+ * spyOn(foo, 'not').andCallThrough();
+ *
+ * // fake example
+ * var foo = {
+ *   not: function(bool) { return !bool; }
+ * }
+ *
+ * // foo.not(val) will return val
+ * spyOn(foo, 'not').andCallFake(function(value) {return value;});
+ *
+ * // mock example
+ * foo.not(7 == 7);
+ * expect(foo.not).toHaveBeenCalled();
+ * expect(foo.not).toHaveBeenCalledWith(true);
+ *
+ * @constructor
+ * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
+ * @param {String} name
+ */
+jasmine.Spy = function(name) {
+  /**
+   * The name of the spy, if provided.
+   */
+  this.identity = name || 'unknown';
+  /**
+   *  Is this Object a spy?
+   */
+  this.isSpy = true;
+  /**
+   * The actual function this spy stubs.
+   */
+  this.plan = function() {
+  };
+  /**
+   * Tracking of the most recent call to the spy.
+   * @example
+   * var mySpy = jasmine.createSpy('foo');
+   * mySpy(1, 2);
+   * mySpy.mostRecentCall.args = [1, 2];
+   */
+  this.mostRecentCall = {};
+
+  /**
+   * Holds arguments for each call to the spy, indexed by call count
+   * @example
+   * var mySpy = jasmine.createSpy('foo');
+   * mySpy(1, 2);
+   * mySpy(7, 8);
+   * mySpy.mostRecentCall.args = [7, 8];
+   * mySpy.argsForCall[0] = [1, 2];
+   * mySpy.argsForCall[1] = [7, 8];
+   */
+  this.argsForCall = [];
+  this.calls = [];
+};
+
+/**
+ * Tells a spy to call through to the actual implemenatation.
+ *
+ * @example
+ * var foo = {
+ *   bar: function() { // do some stuff }
+ * }
+ *
+ * // defining a spy on an existing property: foo.bar
+ * spyOn(foo, 'bar').andCallThrough();
+ */
+jasmine.Spy.prototype.andCallThrough = function() {
+  this.plan = this.originalValue;
+  return this;
+};
+
+/**
+ * For setting the return value of a spy.
+ *
+ * @example
+ * // defining a spy from scratch: foo() returns 'baz'
+ * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() returns 'baz'
+ * spyOn(foo, 'bar').andReturn('baz');
+ *
+ * @param {Object} value
+ */
+jasmine.Spy.prototype.andReturn = function(value) {
+  this.plan = function() {
+    return value;
+  };
+  return this;
+};
+
+/**
+ * For throwing an exception when a spy is called.
+ *
+ * @example
+ * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
+ * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
+ *
+ * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
+ * spyOn(foo, 'bar').andThrow('baz');
+ *
+ * @param {String} exceptionMsg
+ */
+jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
+  this.plan = function() {
+    throw exceptionMsg;
+  };
+  return this;
+};
+
+/**
+ * Calls an alternate implementation when a spy is called.
+ *
+ * @example
+ * var baz = function() {
+ *   // do some stuff, return something
+ * }
+ * // defining a spy from scratch: foo() calls the function baz
+ * var foo = jasmine.createSpy('spy on foo').andCall(baz);
+ *
+ * // defining a spy on an existing property: foo.bar() calls an anonymnous function
+ * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
+ *
+ * @param {Function} fakeFunc
+ */
+jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
+  this.plan = fakeFunc;
+  return this;
+};
+
+/**
+ * Resets all of a spy's the tracking variables so that it can be used again.
+ *
+ * @example
+ * spyOn(foo, 'bar');
+ *
+ * foo.bar();
+ *
+ * expect(foo.bar.callCount).toEqual(1);
+ *
+ * foo.bar.reset();
+ *
+ * expect(foo.bar.callCount).toEqual(0);
+ */
+jasmine.Spy.prototype.reset = function() {
+  this.wasCalled = false;
+  this.callCount = 0;
+  this.argsForCall = [];
+  this.calls = [];
+  this.mostRecentCall = {};
+};
+
+jasmine.createSpy = function(name) {
+
+  var spyObj = function() {
+    spyObj.wasCalled = true;
+    spyObj.callCount++;
+    var args = jasmine.util.argsToArray(arguments);
+    spyObj.mostRecentCall.object = this;
+    spyObj.mostRecentCall.args = args;
+    spyObj.argsForCall.push(args);
+    spyObj.calls.push({object: this, args: args});
+    return spyObj.plan.apply(this, arguments);
+  };
+
+  var spy = new jasmine.Spy(name);
+
+  for (var prop in spy) {
+    spyObj[prop] = spy[prop];
+  }
+
+  spyObj.reset();
+
+  return spyObj;
+};
+
+/**
+ * Determines whether an object is a spy.
+ *
+ * @param {jasmine.Spy|Object} putativeSpy
+ * @returns {Boolean}
+ */
+jasmine.isSpy = function(putativeSpy) {
+  return putativeSpy && putativeSpy.isSpy;
+};
+
+/**
+ * Creates a more complicated spy: an Object that has every property a function that is a spy.  Used for stubbing something
+ * large in one call.
+ *
+ * @param {String} baseName name of spy class
+ * @param {Array} methodNames array of names of methods to make spies
+ */
+jasmine.createSpyObj = function(baseName, methodNames) {
+  if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
+    throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
+  }
+  var obj = {};
+  for (var i = 0; i < methodNames.length; i++) {
+    obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
+  }
+  return obj;
+};
+
+/**
+ * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
+ *
+ * Be careful not to leave calls to <code>jasmine.log</code> in production code.
+ */
+jasmine.log = function() {
+  var spec = jasmine.getEnv().currentSpec;
+  spec.log.apply(spec, arguments);
+};
+
+/**
+ * Function that installs a spy on an existing object's method name.  Used within a Spec to create a spy.
+ *
+ * @example
+ * // spy example
+ * var foo = {
+ *   not: function(bool) { return !bool; }
+ * }
+ * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
+ *
+ * @see jasmine.createSpy
+ * @param obj
+ * @param methodName
+ * @returns a Jasmine spy that can be chained with all spy methods
+ */
+var spyOn = function(obj, methodName) {
+  return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
+};
+if (isCommonJS) exports.spyOn = spyOn;
+
+/**
+ * Creates a Jasmine spec that will be added to the current suite.
+ *
+ * // TODO: pending tests
+ *
+ * @example
+ * it('should be true', function() {
+ *   expect(true).toEqual(true);
+ * });
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var it = function(desc, func) {
+  return jasmine.getEnv().it(desc, func);
+};
+if (isCommonJS) exports.it = it;
+
+/**
+ * Creates a <em>disabled</em> Jasmine spec.
+ *
+ * A convenience method that allows existing specs to be disabled temporarily during development.
+ *
+ * @param {String} desc description of this specification
+ * @param {Function} func defines the preconditions and expectations of the spec
+ */
+var xit = function(desc, func) {
+  return jasmine.getEnv().xit(desc, func);
+};
+if (isCommonJS) exports.xit = xit;
+
+/**
+ * Starts a chain for a Jasmine expectation.
+ *
+ * It is passed an Object that is the actual value and should chain to one of the many
+ * jasmine.Matchers functions.
+ *
+ * @param {Object} actual Actual value to test against and expected value
+ */
+var expect = function(actual) {
+  return jasmine.getEnv().currentSpec.expect(actual);
+};
+if (isCommonJS) exports.expect = expect;
+
+/**
+ * Defines part of a jasmine spec.  Used in cominbination with waits or waitsFor in asynchrnous specs.
+ *
+ * @param {Function} func Function that defines part of a jasmine spec.
+ */
+var runs = function(func) {
+  jasmine.getEnv().currentSpec.runs(func);
+};
+if (isCommonJS) exports.runs = runs;
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+var waits = function(timeout) {
+  jasmine.getEnv().currentSpec.waits(timeout);
+};
+if (isCommonJS) exports.waits = waits;
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+  jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
+};
+if (isCommonJS) exports.waitsFor = waitsFor;
+
+/**
+ * A function that is called before each spec in a suite.
+ *
+ * Used for spec setup, including validating assumptions.
+ *
+ * @param {Function} beforeEachFunction
+ */
+var beforeEach = function(beforeEachFunction) {
+  jasmine.getEnv().beforeEach(beforeEachFunction);
+};
+if (isCommonJS) exports.beforeEach = beforeEach;
+
+/**
+ * A function that is called after each spec in a suite.
+ *
+ * Used for restoring any state that is hijacked during spec execution.
+ *
+ * @param {Function} afterEachFunction
+ */
+var afterEach = function(afterEachFunction) {
+  jasmine.getEnv().afterEach(afterEachFunction);
+};
+if (isCommonJS) exports.afterEach = afterEach;
+
+/**
+ * Defines a suite of specifications.
+ *
+ * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
+ * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
+ * of setup in some tests.
+ *
+ * @example
+ * // TODO: a simple suite
+ *
+ * // TODO: a simple suite with a nested describe block
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var describe = function(description, specDefinitions) {
+  return jasmine.getEnv().describe(description, specDefinitions);
+};
+if (isCommonJS) exports.describe = describe;
+
+/**
+ * Disables a suite of specifications.  Used to disable some suites in a file, or files, temporarily during development.
+ *
+ * @param {String} description A string, usually the class under test.
+ * @param {Function} specDefinitions function that defines several specs.
+ */
+var xdescribe = function(description, specDefinitions) {
+  return jasmine.getEnv().xdescribe(description, specDefinitions);
+};
+if (isCommonJS) exports.xdescribe = xdescribe;
+
+
+// Provide the XMLHttpRequest class for IE 5.x-6.x:
+jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
+  function tryIt(f) {
+    try {
+      return f();
+    } catch(e) {
+    }
+    return null;
+  }
+
+  var xhr = tryIt(function() {
+    return new ActiveXObject("Msxml2.XMLHTTP.6.0");
+  }) ||
+    tryIt(function() {
+      return new ActiveXObject("Msxml2.XMLHTTP.3.0");
+    }) ||
+    tryIt(function() {
+      return new ActiveXObject("Msxml2.XMLHTTP");
+    }) ||
+    tryIt(function() {
+      return new ActiveXObject("Microsoft.XMLHTTP");
+    });
+
+  if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
+
+  return xhr;
+} : XMLHttpRequest;
+/**
+ * @namespace
+ */
+jasmine.util = {};
+
+/**
+ * Declare that a child class inherit it's prototype from the parent class.
+ *
+ * @private
+ * @param {Function} childClass
+ * @param {Function} parentClass
+ */
+jasmine.util.inherit = function(childClass, parentClass) {
+  /**
+   * @private
+   */
+  var subclass = function() {
+  };
+  subclass.prototype = parentClass.prototype;
+  childClass.prototype = new subclass();
+};
+
+jasmine.util.formatException = function(e) {
+  var lineNumber;
+  if (e.line) {
+    lineNumber = e.line;
+  }
+  else if (e.lineNumber) {
+    lineNumber = e.lineNumber;
+  }
+
+  var file;
+
+  if (e.sourceURL) {
+    file = e.sourceURL;
+  }
+  else if (e.fileName) {
+    file = e.fileName;
+  }
+
+  var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
+
+  if (file && lineNumber) {
+    message += ' in ' + file + ' (line ' + lineNumber + ')';
+  }
+
+  return message;
+};
+
+jasmine.util.htmlEscape = function(str) {
+  if (!str) return str;
+  return str.replace(/&/g, '&amp;')
+    .replace(/</g, '&lt;')
+    .replace(/>/g, '&gt;');
+};
+
+jasmine.util.argsToArray = function(args) {
+  var arrayOfArgs = [];
+  for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
+  return arrayOfArgs;
+};
+
+jasmine.util.extend = function(destination, source) {
+  for (var property in source) destination[property] = source[property];
+  return destination;
+};
+
+/**
+ * Environment for Jasmine
+ *
+ * @constructor
+ */
+jasmine.Env = function() {
+  this.currentSpec = null;
+  this.currentSuite = null;
+  this.currentRunner_ = new jasmine.Runner(this);
+
+  this.reporter = new jasmine.MultiReporter();
+
+  this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
+  this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
+  this.lastUpdate = 0;
+  this.specFilter = function() {
+    return true;
+  };
+
+  this.nextSpecId_ = 0;
+  this.nextSuiteId_ = 0;
+  this.equalityTesters_ = [];
+
+  // wrap matchers
+  this.matchersClass = function() {
+    jasmine.Matchers.apply(this, arguments);
+  };
+  jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
+
+  jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
+};
+
+
+jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
+jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
+jasmine.Env.prototype.setInterval = jasmine.setInterval;
+jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
+
+/**
+ * @returns an object containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.version = function () {
+  if (jasmine.version_) {
+    return jasmine.version_;
+  } else {
+    throw new Error('Version not set');
+  }
+};
+
+/**
+ * @returns string containing jasmine version build info, if set.
+ */
+jasmine.Env.prototype.versionString = function() {
+  if (!jasmine.version_) {
+    return "version unknown";
+  }
+
+  var version = this.version();
+  var versionString = version.major + "." + version.minor + "." + version.build;
+  if (version.release_candidate) {
+    versionString += ".rc" + version.release_candidate;
+  }
+  versionString += " revision " + version.revision;
+  return versionString;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSpecId = function () {
+  return this.nextSpecId_++;
+};
+
+/**
+ * @returns a sequential integer starting at 0
+ */
+jasmine.Env.prototype.nextSuiteId = function () {
+  return this.nextSuiteId_++;
+};
+
+/**
+ * Register a reporter to receive status updates from Jasmine.
+ * @param {jasmine.Reporter} reporter An object which will receive status updates.
+ */
+jasmine.Env.prototype.addReporter = function(reporter) {
+  this.reporter.addReporter(reporter);
+};
+
+jasmine.Env.prototype.execute = function() {
+  this.currentRunner_.execute();
+};
+
+jasmine.Env.prototype.describe = function(description, specDefinitions) {
+  var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
+
+  var parentSuite = this.currentSuite;
+  if (parentSuite) {
+    parentSuite.add(suite);
+  } else {
+    this.currentRunner_.add(suite);
+  }
+
+  this.currentSuite = suite;
+
+  var declarationError = null;
+  try {
+    specDefinitions.call(suite);
+  } catch(e) {
+    declarationError = e;
+  }
+
+  if (declarationError) {
+    this.it("encountered a declaration exception", function() {
+      throw declarationError;
+    });
+  }
+
+  this.currentSuite = parentSuite;
+
+  return suite;
+};
+
+jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
+  if (this.currentSuite) {
+    this.currentSuite.beforeEach(beforeEachFunction);
+  } else {
+    this.currentRunner_.beforeEach(beforeEachFunction);
+  }
+};
+
+jasmine.Env.prototype.currentRunner = function () {
+  return this.currentRunner_;
+};
+
+jasmine.Env.prototype.afterEach = function(afterEachFunction) {
+  if (this.currentSuite) {
+    this.currentSuite.afterEach(afterEachFunction);
+  } else {
+    this.currentRunner_.afterEach(afterEachFunction);
+  }
+
+};
+
+jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
+  return {
+    execute: function() {
+    }
+  };
+};
+
+jasmine.Env.prototype.it = function(description, func) {
+  var spec = new jasmine.Spec(this, this.currentSuite, description);
+  this.currentSuite.add(spec);
+  this.currentSpec = spec;
+
+  if (func) {
+    spec.runs(func);
+  }
+
+  return spec;
+};
+
+jasmine.Env.prototype.xit = function(desc, func) {
+  return {
+    id: this.nextSpecId(),
+    runs: function() {
+    }
+  };
+};
+
+jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
+  if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
+    return true;
+  }
+
+  a.__Jasmine_been_here_before__ = b;
+  b.__Jasmine_been_here_before__ = a;
+
+  var hasKey = function(obj, keyName) {
+    return obj !== null && obj[keyName] !== jasmine.undefined;
+  };
+
+  for (var property in b) {
+    if (!hasKey(a, property) && hasKey(b, property)) {
+      mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+    }
+  }
+  for (property in a) {
+    if (!hasKey(b, property) && hasKey(a, property)) {
+      mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
+    }
+  }
+  for (property in b) {
+    if (property == '__Jasmine_been_here_before__') continue;
+    if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
+      mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
+    }
+  }
+
+  if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
+    mismatchValues.push("arrays were not the same length");
+  }
+
+  delete a.__Jasmine_been_here_before__;
+  delete b.__Jasmine_been_here_before__;
+  return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+};
+
+jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
+  mismatchKeys = mismatchKeys || [];
+  mismatchValues = mismatchValues || [];
+
+  for (var i = 0; i < this.equalityTesters_.length; i++) {
+    var equalityTester = this.equalityTesters_[i];
+    var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
+    if (result !== jasmine.undefined) return result;
+  }
+
+  if (a === b) return true;
+
+  if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
+    return (a == jasmine.undefined && b == jasmine.undefined);
+  }
+
+  if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
+    return a === b;
+  }
+
+  if (a instanceof Date && b instanceof Date) {
+    return a.getTime() == b.getTime();
+  }
+
+  if (a.jasmineMatches) {
+    return a.jasmineMatches(b);
+  }
+
+  if (b.jasmineMatches) {
+    return b.jasmineMatches(a);
+  }
+
+  if (a instanceof jasmine.Matchers.ObjectContaining) {
+    return a.matches(b);
+  }
+
+  if (b instanceof jasmine.Matchers.ObjectContaining) {
+    return b.matches(a);
+  }
+
+  if (jasmine.isString_(a) && jasmine.isString_(b)) {
+    return (a == b);
+  }
+
+  if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
+    return (a == b);
+  }
+
+  if (typeof a === "object" && typeof b === "object") {
+    return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
+  }
+
+  //Straight check
+  return (a === b);
+};
+
+jasmine.Env.prototype.contains_ = function(haystack, needle) {
+  if (jasmine.isArray_(haystack)) {
+    for (var i = 0; i < haystack.length; i++) {
+      if (this.equals_(haystack[i], needle)) return true;
+    }
+    return false;
+  }
+  return haystack.indexOf(needle) >= 0;
+};
+
+jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
+  this.equalityTesters_.push(equalityTester);
+};
+/** No-op base class for Jasmine reporters.
+ *
+ * @constructor
+ */
+jasmine.Reporter = function() {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.reportSpecResults = function(spec) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.Reporter.prototype.log = function(str) {
+};
+
+/**
+ * Blocks are functions with executable code that make up a spec.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {Function} func
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Block = function(env, func, spec) {
+  this.env = env;
+  this.func = func;
+  this.spec = spec;
+};
+
+jasmine.Block.prototype.execute = function(onComplete) {  
+  try {
+    this.func.apply(this.spec);
+  } catch (e) {
+    this.spec.fail(e);
+  }
+  onComplete();
+};
+/** JavaScript API reporter.
+ *
+ * @constructor
+ */
+jasmine.JsApiReporter = function() {
+  this.started = false;
+  this.finished = false;
+  this.suites_ = [];
+  this.results_ = {};
+};
+
+jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
+  this.started = true;
+  var suites = runner.topLevelSuites();
+  for (var i = 0; i < suites.length; i++) {
+    var suite = suites[i];
+    this.suites_.push(this.summarize_(suite));
+  }
+};
+
+jasmine.JsApiReporter.prototype.suites = function() {
+  return this.suites_;
+};
+
+jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
+  var isSuite = suiteOrSpec instanceof jasmine.Suite;
+  var summary = {
+    id: suiteOrSpec.id,
+    name: suiteOrSpec.description,
+    type: isSuite ? 'suite' : 'spec',
+    children: []
+  };
+  
+  if (isSuite) {
+    var children = suiteOrSpec.children();
+    for (var i = 0; i < children.length; i++) {
+      summary.children.push(this.summarize_(children[i]));
+    }
+  }
+  return summary;
+};
+
+jasmine.JsApiReporter.prototype.results = function() {
+  return this.results_;
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
+  return this.results_[specId];
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
+  this.finished = true;
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
+  this.results_[spec.id] = {
+    messages: spec.results().getItems(),
+    result: spec.results().failedCount > 0 ? "failed" : "passed"
+  };
+};
+
+//noinspection JSUnusedLocalSymbols
+jasmine.JsApiReporter.prototype.log = function(str) {
+};
+
+jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
+  var results = {};
+  for (var i = 0; i < specIds.length; i++) {
+    var specId = specIds[i];
+    results[specId] = this.summarizeResult_(this.results_[specId]);
+  }
+  return results;
+};
+
+jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
+  var summaryMessages = [];
+  var messagesLength = result.messages.length;
+  for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
+    var resultMessage = result.messages[messageIndex];
+    summaryMessages.push({
+      text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
+      passed: resultMessage.passed ? resultMessage.passed() : true,
+      type: resultMessage.type,
+      message: resultMessage.message,
+      trace: {
+        stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
+      }
+    });
+  }
+
+  return {
+    result : result.result,
+    messages : summaryMessages
+  };
+};
+
+/**
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param actual
+ * @param {jasmine.Spec} spec
+ */
+jasmine.Matchers = function(env, actual, spec, opt_isNot) {
+  this.env = env;
+  this.actual = actual;
+  this.spec = spec;
+  this.isNot = opt_isNot || false;
+  this.reportWasCalled_ = false;
+};
+
+// todo: @deprecated as of Jasmine 0.11, remove soon [xw]
+jasmine.Matchers.pp = function(str) {
+  throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
+};
+
+// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
+jasmine.Matchers.prototype.report = function(result, failing_message, details) {
+  throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
+};
+
+jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
+  for (var methodName in prototype) {
+    if (methodName == 'report') continue;
+    var orig = prototype[methodName];
+    matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
+  }
+};
+
+jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
+  return function() {
+    var matcherArgs = jasmine.util.argsToArray(arguments);
+    var result = matcherFunction.apply(this, arguments);
+
+    if (this.isNot) {
+      result = !result;
+    }
+
+    if (this.reportWasCalled_) return result;
+
+    var message;
+    if (!result) {
+      if (this.message) {
+        message = this.message.apply(this, arguments);
+        if (jasmine.isArray_(message)) {
+          message = message[this.isNot ? 1 : 0];
+        }
+      } else {
+        var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
+        message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
+        if (matcherArgs.length > 0) {
+          for (var i = 0; i < matcherArgs.length; i++) {
+            if (i > 0) message += ",";
+            message += " " + jasmine.pp(matcherArgs[i]);
+          }
+        }
+        message += ".";
+      }
+    }
+    var expectationResult = new jasmine.ExpectationResult({
+      matcherName: matcherName,
+      passed: result,
+      expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
+      actual: this.actual,
+      message: message
+    });
+    this.spec.addMatcherResult(expectationResult);
+    return jasmine.undefined;
+  };
+};
+
+
+
+
+/**
+ * toBe: compares the actual to the expected using ===
+ * @param expected
+ */
+jasmine.Matchers.prototype.toBe = function(expected) {
+  return this.actual === expected;
+};
+
+/**
+ * toNotBe: compares the actual to the expected using !==
+ * @param expected
+ * @deprecated as of 1.0. Use not.toBe() instead.
+ */
+jasmine.Matchers.prototype.toNotBe = function(expected) {
+  return this.actual !== expected;
+};
+
+/**
+ * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toEqual = function(expected) {
+  return this.env.equals_(this.actual, expected);
+};
+
+/**
+ * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
+ * @param expected
+ * @deprecated as of 1.0. Use not.toEqual() instead.
+ */
+jasmine.Matchers.prototype.toNotEqual = function(expected) {
+  return !this.env.equals_(this.actual, expected);
+};
+
+/**
+ * Matcher that compares the actual to the expected using a regular expression.  Constructs a RegExp, so takes
+ * a pattern or a String.
+ *
+ * @param expected
+ */
+jasmine.Matchers.prototype.toMatch = function(expected) {
+  return new RegExp(expected).test(this.actual);
+};
+
+/**
+ * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
+ * @param expected
+ * @deprecated as of 1.0. Use not.toMatch() instead.
+ */
+jasmine.Matchers.prototype.toNotMatch = function(expected) {
+  return !(new RegExp(expected).test(this.actual));
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeDefined = function() {
+  return (this.actual !== jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to jasmine.undefined.
+ */
+jasmine.Matchers.prototype.toBeUndefined = function() {
+  return (this.actual === jasmine.undefined);
+};
+
+/**
+ * Matcher that compares the actual to null.
+ */
+jasmine.Matchers.prototype.toBeNull = function() {
+  return (this.actual === null);
+};
+
+/**
+ * Matcher that boolean not-nots the actual.
+ */
+jasmine.Matchers.prototype.toBeTruthy = function() {
+  return !!this.actual;
+};
+
+
+/**
+ * Matcher that boolean nots the actual.
+ */
+jasmine.Matchers.prototype.toBeFalsy = function() {
+  return !this.actual;
+};
+
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called.
+ */
+jasmine.Matchers.prototype.toHaveBeenCalled = function() {
+  if (arguments.length > 0) {
+    throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
+  }
+
+  if (!jasmine.isSpy(this.actual)) {
+    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+  }
+
+  this.message = function() {
+    return [
+      "Expected spy " + this.actual.identity + " to have been called.",
+      "Expected spy " + this.actual.identity + " not to have been called."
+    ];
+  };
+
+  return this.actual.wasCalled;
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
+jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was not called.
+ *
+ * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
+ */
+jasmine.Matchers.prototype.wasNotCalled = function() {
+  if (arguments.length > 0) {
+    throw new Error('wasNotCalled does not take arguments');
+  }
+
+  if (!jasmine.isSpy(this.actual)) {
+    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+  }
+
+  this.message = function() {
+    return [
+      "Expected spy " + this.actual.identity + " to not have been called.",
+      "Expected spy " + this.actual.identity + " to have been called."
+    ];
+  };
+
+  return !this.actual.wasCalled;
+};
+
+/**
+ * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
+ *
+ * @example
+ *
+ */
+jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
+  var expectedArgs = jasmine.util.argsToArray(arguments);
+  if (!jasmine.isSpy(this.actual)) {
+    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+  }
+  this.message = function() {
+    if (this.actual.callCount === 0) {
+      // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw]
+      return [
+        "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.",
+        "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."
+      ];
+    } else {
+      return [
+        "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall),
+        "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall)
+      ];
+    }
+  };
+
+  return this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
+
+/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
+jasmine.Matchers.prototype.wasNotCalledWith = function() {
+  var expectedArgs = jasmine.util.argsToArray(arguments);
+  if (!jasmine.isSpy(this.actual)) {
+    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
+  }
+
+  this.message = function() {
+    return [
+      "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
+      "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
+    ];
+  };
+
+  return !this.env.contains_(this.actual.argsForCall, expectedArgs);
+};
+
+/**
+ * Matcher that checks that the expected item is an element in the actual Array.
+ *
+ * @param {Object} expected
+ */
+jasmine.Matchers.prototype.toContain = function(expected) {
+  return this.env.contains_(this.actual, expected);
+};
+
+/**
+ * Matcher that checks that the expected item is NOT an element in the actual Array.
+ *
+ * @param {Object} expected
+ * @deprecated as of 1.0. Use not.toContain() instead.
+ */
+jasmine.Matchers.prototype.toNotContain = function(expected) {
+  return !this.env.contains_(this.actual, expected);
+};
+
+jasmine.Matchers.prototype.toBeLessThan = function(expected) {
+  return this.actual < expected;
+};
+
+jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
+  return this.actual > expected;
+};
+
+/**
+ * Matcher that checks that the expected item is equal to the actual item
+ * up to a given level of decimal precision (default 2).
+ *
+ * @param {Number} expected
+ * @param {Number} precision
+ */
+jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
+  if (!(precision === 0)) {
+    precision = precision || 2;
+  }
+  var multiplier = Math.pow(10, precision);
+  var actual = Math.round(this.actual * multiplier);
+  expected = Math.round(expected * multiplier);
+  return expected == actual;
+};
+
+/**
+ * Matcher that checks that the expected exception was thrown by the actual.
+ *
+ * @param {String} expected
+ */
+jasmine.Matchers.prototype.toThrow = function(expected) {
+  var result = false;
+  var exception;
+  if (typeof this.actual != 'function') {
+    throw new Error('Actual is not a function');
+  }
+  try {
+    this.actual();
+  } catch (e) {
+    exception = e;
+  }
+  if (exception) {
+    result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
+  }
+
+  var not = this.isNot ? "not " : "";
+
+  this.message = function() {
+    if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
+      return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
+    } else {
+      return "Expected function to throw an exception.";
+    }
+  };
+
+  return result;
+};
+
+jasmine.Matchers.Any = function(expectedClass) {
+  this.expectedClass = expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
+  if (this.expectedClass == String) {
+    return typeof other == 'string' || other instanceof String;
+  }
+
+  if (this.expectedClass == Number) {
+    return typeof other == 'number' || other instanceof Number;
+  }
+
+  if (this.expectedClass == Function) {
+    return typeof other == 'function' || other instanceof Function;
+  }
+
+  if (this.expectedClass == Object) {
+    return typeof other == 'object';
+  }
+
+  return other instanceof this.expectedClass;
+};
+
+jasmine.Matchers.Any.prototype.jasmineToString = function() {
+  return '<jasmine.any(' + this.expectedClass + ')>';
+};
+
+jasmine.Matchers.ObjectContaining = function (sample) {
+  this.sample = sample;
+};
+
+jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
+  mismatchKeys = mismatchKeys || [];
+  mismatchValues = mismatchValues || [];
+
+  var env = jasmine.getEnv();
+
+  var hasKey = function(obj, keyName) {
+    return obj != null && obj[keyName] !== jasmine.undefined;
+  };
+
+  for (var property in this.sample) {
+    if (!hasKey(other, property) && hasKey(this.sample, property)) {
+      mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
+    }
+    else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
+      mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
+    }
+  }
+
+  return (mismatchKeys.length === 0 && mismatchValues.length === 0);
+};
+
+jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
+  return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
+};
+// Mock setTimeout, clearTimeout
+// Contributed by Pivotal Computer Systems, www.pivotalsf.com
+
+jasmine.FakeTimer = function() {
+  this.reset();
+
+  var self = this;
+  self.setTimeout = function(funcToCall, millis) {
+    self.timeoutsMade++;
+    self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
+    return self.timeoutsMade;
+  };
+
+  self.setInterval = function(funcToCall, millis) {
+    self.timeoutsMade++;
+    self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
+    return self.timeoutsMade;
+  };
+
+  self.clearTimeout = function(timeoutKey) {
+    self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+  };
+
+  self.clearInterval = function(timeoutKey) {
+    self.scheduledFunctions[timeoutKey] = jasmine.undefined;
+  };
+
+};
+
+jasmine.FakeTimer.prototype.reset = function() {
+  this.timeoutsMade = 0;
+  this.scheduledFunctions = {};
+  this.nowMillis = 0;
+};
+
+jasmine.FakeTimer.prototype.tick = function(millis) {
+  var oldMillis = this.nowMillis;
+  var newMillis = oldMillis + millis;
+  this.runFunctionsWithinRange(oldMillis, newMillis);
+  this.nowMillis = newMillis;
+};
+
+jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
+  var scheduledFunc;
+  var funcsToRun = [];
+  for (var timeoutKey in this.scheduledFunctions) {
+    scheduledFunc = this.scheduledFunctions[timeoutKey];
+    if (scheduledFunc != jasmine.undefined &&
+        scheduledFunc.runAtMillis >= oldMillis &&
+        scheduledFunc.runAtMillis <= nowMillis) {
+      funcsToRun.push(scheduledFunc);
+      this.scheduledFunctions[timeoutKey] = jasmine.undefined;
+    }
+  }
+
+  if (funcsToRun.length > 0) {
+    funcsToRun.sort(function(a, b) {
+      return a.runAtMillis - b.runAtMillis;
+    });
+    for (var i = 0; i < funcsToRun.length; ++i) {
+      try {
+        var funcToRun = funcsToRun[i];
+        this.nowMillis = funcToRun.runAtMillis;
+        funcToRun.funcToCall();
+        if (funcToRun.recurring) {
+          this.scheduleFunction(funcToRun.timeoutKey,
+              funcToRun.funcToCall,
+              funcToRun.millis,
+              true);
+        }
+      } catch(e) {
+      }
+    }
+    this.runFunctionsWithinRange(oldMillis, nowMillis);
+  }
+};
+
+jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
+  this.scheduledFunctions[timeoutKey] = {
+    runAtMillis: this.nowMillis + millis,
+    funcToCall: funcToCall,
+    recurring: recurring,
+    timeoutKey: timeoutKey,
+    millis: millis
+  };
+};
+
+/**
+ * @namespace
+ */
+jasmine.Clock = {
+  defaultFakeTimer: new jasmine.FakeTimer(),
+
+  reset: function() {
+    jasmine.Clock.assertInstalled();
+    jasmine.Clock.defaultFakeTimer.reset();
+  },
+
+  tick: function(millis) {
+    jasmine.Clock.assertInstalled();
+    jasmine.Clock.defaultFakeTimer.tick(millis);
+  },
+
+  runFunctionsWithinRange: function(oldMillis, nowMillis) {
+    jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
+  },
+
+  scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
+    jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
+  },
+
+  useMock: function() {
+    if (!jasmine.Clock.isInstalled()) {
+      var spec = jasmine.getEnv().currentSpec;
+      spec.after(jasmine.Clock.uninstallMock);
+
+      jasmine.Clock.installMock();
+    }
+  },
+
+  installMock: function() {
+    jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
+  },
+
+  uninstallMock: function() {
+    jasmine.Clock.assertInstalled();
+    jasmine.Clock.installed = jasmine.Clock.real;
+  },
+
+  real: {
+    setTimeout: jasmine.getGlobal().setTimeout,
+    clearTimeout: jasmine.getGlobal().clearTimeout,
+    setInterval: jasmine.getGlobal().setInterval,
+    clearInterval: jasmine.getGlobal().clearInterval
+  },
+
+  assertInstalled: function() {
+    if (!jasmine.Clock.isInstalled()) {
+      throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
+    }
+  },
+
+  isInstalled: function() {
+    return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
+  },
+
+  installed: null
+};
+jasmine.Clock.installed = jasmine.Clock.real;
+
+//else for IE support
+jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
+  if (jasmine.Clock.installed.setTimeout.apply) {
+    return jasmine.Clock.installed.setTimeout.apply(this, arguments);
+  } else {
+    return jasmine.Clock.installed.setTimeout(funcToCall, millis);
+  }
+};
+
+jasmine.getGlobal().setInterval = function(funcToCall, millis) {
+  if (jasmine.Clock.installed.setInterval.apply) {
+    return jasmine.Clock.installed.setInterval.apply(this, arguments);
+  } else {
+    return jasmine.Clock.installed.setInterval(funcToCall, millis);
+  }
+};
+
+jasmine.getGlobal().clearTimeout = function(timeoutKey) {
+  if (jasmine.Clock.installed.clearTimeout.apply) {
+    return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
+  } else {
+    return jasmine.Clock.installed.clearTimeout(timeoutKey);
+  }
+};
+
+jasmine.getGlobal().clearInterval = function(timeoutKey) {
+  if (jasmine.Clock.installed.clearTimeout.apply) {
+    return jasmine.Clock.installed.clearInterval.apply(this, arguments);
+  } else {
+    return jasmine.Clock.installed.clearInterval(timeoutKey);
+  }
+};
+
+/**
+ * @constructor
+ */
+jasmine.MultiReporter = function() {
+  this.subReporters_ = [];
+};
+jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
+
+jasmine.MultiReporter.prototype.addReporter = function(reporter) {
+  this.subReporters_.push(reporter);
+};
+
+(function() {
+  var functionNames = [
+    "reportRunnerStarting",
+    "reportRunnerResults",
+    "reportSuiteResults",
+    "reportSpecStarting",
+    "reportSpecResults",
+    "log"
+  ];
+  for (var i = 0; i < functionNames.length; i++) {
+    var functionName = functionNames[i];
+    jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
+      return function() {
+        for (var j = 0; j < this.subReporters_.length; j++) {
+          var subReporter = this.subReporters_[j];
+          if (subReporter[functionName]) {
+            subReporter[functionName].apply(subReporter, arguments);
+          }
+        }
+      };
+    })(functionName);
+  }
+})();
+/**
+ * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
+ *
+ * @constructor
+ */
+jasmine.NestedResults = function() {
+  /**
+   * The total count of results
+   */
+  this.totalCount = 0;
+  /**
+   * Number of passed results
+   */
+  this.passedCount = 0;
+  /**
+   * Number of failed results
+   */
+  this.failedCount = 0;
+  /**
+   * Was this suite/spec skipped?
+   */
+  this.skipped = false;
+  /**
+   * @ignore
+   */
+  this.items_ = [];
+};
+
+/**
+ * Roll up the result counts.
+ *
+ * @param result
+ */
+jasmine.NestedResults.prototype.rollupCounts = function(result) {
+  this.totalCount += result.totalCount;
+  this.passedCount += result.passedCount;
+  this.failedCount += result.failedCount;
+};
+
+/**
+ * Adds a log message.
+ * @param values Array of message parts which will be concatenated later.
+ */
+jasmine.NestedResults.prototype.log = function(values) {
+  this.items_.push(new jasmine.MessageResult(values));
+};
+
+/**
+ * Getter for the results: message & results.
+ */
+jasmine.NestedResults.prototype.getItems = function() {
+  return this.items_;
+};
+
+/**
+ * Adds a result, tracking counts (total, passed, & failed)
+ * @param {jasmine.ExpectationResult|jasmine.NestedResults} result
+ */
+jasmine.NestedResults.prototype.addResult = function(result) {
+  if (result.type != 'log') {
+    if (result.items_) {
+      this.rollupCounts(result);
+    } else {
+      this.totalCount++;
+      if (result.passed()) {
+        this.passedCount++;
+      } else {
+        this.failedCount++;
+      }
+    }
+  }
+  this.items_.push(result);
+};
+
+/**
+ * @returns {Boolean} True if <b>everything</b> below passed
+ */
+jasmine.NestedResults.prototype.passed = function() {
+  return this.passedCount === this.totalCount;
+};
+/**
+ * Base class for pretty printing for expectation results.
+ */
+jasmine.PrettyPrinter = function() {
+  this.ppNestLevel_ = 0;
+};
+
+/**
+ * Formats a value in a nice, human-readable string.
+ *
+ * @param value
+ */
+jasmine.PrettyPrinter.prototype.format = function(value) {
+  if (this.ppNestLevel_ > 40) {
+    throw new Error('jasmine.PrettyPrinter: format() nested too deeply!');
+  }
+
+  this.ppNestLevel_++;
+  try {
+    if (value === jasmine.undefined) {
+      this.emitScalar('undefined');
+    } else if (value === null) {
+      this.emitScalar('null');
+    } else if (value === jasmine.getGlobal()) {
+      this.emitScalar('<global>');
+    } else if (value.jasmineToString) {
+      this.emitScalar(value.jasmineToString());
+    } else if (typeof value === 'string') {
+      this.emitString(value);
+    } else if (jasmine.isSpy(value)) {
+      this.emitScalar("spy on " + value.identity);
+    } else if (value instanceof RegExp) {
+      this.emitScalar(value.toString());
+    } else if (typeof value === 'function') {
+      this.emitScalar('Function');
+    } else if (typeof value.nodeType === 'number') {
+      this.emitScalar('HTMLNode');
+    } else if (value instanceof Date) {
+      this.emitScalar('Date(' + value + ')');
+    } else if (value.__Jasmine_been_here_before__) {
+      this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
+    } else if (jasmine.isArray_(value) || typeof value == 'object') {
+      value.__Jasmine_been_here_before__ = true;
+      if (jasmine.isArray_(value)) {
+        this.emitArray(value);
+      } else {
+        this.emitObject(value);
+      }
+      delete value.__Jasmine_been_here_before__;
+    } else {
+      this.emitScalar(value.toString());
+    }
+  } finally {
+    this.ppNestLevel_--;
+  }
+};
+
+jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
+  for (var property in obj) {
+    if (property == '__Jasmine_been_here_before__') continue;
+    fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined && 
+                                         obj.__lookupGetter__(property) !== null) : false);
+  }
+};
+
+jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
+jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
+
+jasmine.StringPrettyPrinter = function() {
+  jasmine.PrettyPrinter.call(this);
+
+  this.string = '';
+};
+jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
+
+jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
+  this.append(value);
+};
+
+jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
+  this.append("'" + value + "'");
+};
+
+jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
+  this.append('[ ');
+  for (var i = 0; i < array.length; i++) {
+    if (i > 0) {
+      this.append(', ');
+    }
+    this.format(array[i]);
+  }
+  this.append(' ]');
+};
+
+jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
+  var self = this;
+  this.append('{ ');
+  var first = true;
+
+  this.iterateObject(obj, function(property, isGetter) {
+    if (first) {
+      first = false;
+    } else {
+      self.append(', ');
+    }
+
+    self.append(property);
+    self.append(' : ');
+    if (isGetter) {
+      self.append('<getter>');
+    } else {
+      self.format(obj[property]);
+    }
+  });
+
+  this.append(' }');
+};
+
+jasmine.StringPrettyPrinter.prototype.append = function(value) {
+  this.string += value;
+};
+jasmine.Queue = function(env) {
+  this.env = env;
+  this.blocks = [];
+  this.running = false;
+  this.index = 0;
+  this.offset = 0;
+  this.abort = false;
+};
+
+jasmine.Queue.prototype.addBefore = function(block) {
+  this.blocks.unshift(block);
+};
+
+jasmine.Queue.prototype.add = function(block) {
+  this.blocks.push(block);
+};
+
+jasmine.Queue.prototype.insertNext = function(block) {
+  this.blocks.splice((this.index + this.offset + 1), 0, block);
+  this.offset++;
+};
+
+jasmine.Queue.prototype.start = function(onComplete) {
+  this.running = true;
+  this.onComplete = onComplete;
+  this.next_();
+};
+
+jasmine.Queue.prototype.isRunning = function() {
+  return this.running;
+};
+
+jasmine.Queue.LOOP_DONT_RECURSE = true;
+
+jasmine.Queue.prototype.next_ = function() {
+  var self = this;
+  var goAgain = true;
+
+  while (goAgain) {
+    goAgain = false;
+    
+    if (self.index < self.blocks.length && !this.abort) {
+      var calledSynchronously = true;
+      var completedSynchronously = false;
+
+      var onComplete = function () {
+        if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
+          completedSynchronously = true;
+          return;
+        }
+
+        if (self.blocks[self.index].abort) {
+          self.abort = true;
+        }
+
+        self.offset = 0;
+        self.index++;
+
+        var now = new Date().getTime();
+        if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
+          self.env.lastUpdate = now;
+          self.env.setTimeout(function() {
+            self.next_();
+          }, 0);
+        } else {
+          if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
+            goAgain = true;
+          } else {
+            self.next_();
+          }
+        }
+      };
+      self.blocks[self.index].execute(onComplete);
+
+      calledSynchronously = false;
+      if (completedSynchronously) {
+        onComplete();
+      }
+      
+    } else {
+      self.running = false;
+      if (self.onComplete) {
+        self.onComplete();
+      }
+    }
+  }
+};
+
+jasmine.Queue.prototype.results = function() {
+  var results = new jasmine.NestedResults();
+  for (var i = 0; i < this.blocks.length; i++) {
+    if (this.blocks[i].results) {
+      results.addResult(this.blocks[i].results());
+    }
+  }
+  return results;
+};
+
+
+/**
+ * Runner
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ */
+jasmine.Runner = function(env) {
+  var self = this;
+  self.env = env;
+  self.queue = new jasmine.Queue(env);
+  self.before_ = [];
+  self.after_ = [];
+  self.suites_ = [];
+};
+
+jasmine.Runner.prototype.execute = function() {
+  var self = this;
+  if (self.env.reporter.reportRunnerStarting) {
+    self.env.reporter.reportRunnerStarting(this);
+  }
+  self.queue.start(function () {
+    self.finishCallback();
+  });
+};
+
+jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
+  beforeEachFunction.typeName = 'beforeEach';
+  this.before_.splice(0,0,beforeEachFunction);
+};
+
+jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
+  afterEachFunction.typeName = 'afterEach';
+  this.after_.splice(0,0,afterEachFunction);
+};
+
+
+jasmine.Runner.prototype.finishCallback = function() {
+  this.env.reporter.reportRunnerResults(this);
+};
+
+jasmine.Runner.prototype.addSuite = function(suite) {
+  this.suites_.push(suite);
+};
+
+jasmine.Runner.prototype.add = function(block) {
+  if (block instanceof jasmine.Suite) {
+    this.addSuite(block);
+  }
+  this.queue.add(block);
+};
+
+jasmine.Runner.prototype.specs = function () {
+  var suites = this.suites();
+  var specs = [];
+  for (var i = 0; i < suites.length; i++) {
+    specs = specs.concat(suites[i].specs());
+  }
+  return specs;
+};
+
+jasmine.Runner.prototype.suites = function() {
+  return this.suites_;
+};
+
+jasmine.Runner.prototype.topLevelSuites = function() {
+  var topLevelSuites = [];
+  for (var i = 0; i < this.suites_.length; i++) {
+    if (!this.suites_[i].parentSuite) {
+      topLevelSuites.push(this.suites_[i]);
+    }
+  }
+  return topLevelSuites;
+};
+
+jasmine.Runner.prototype.results = function() {
+  return this.queue.results();
+};
+/**
+ * Internal representation of a Jasmine specification, or test.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {jasmine.Suite} suite
+ * @param {String} description
+ */
+jasmine.Spec = function(env, suite, description) {
+  if (!env) {
+    throw new Error('jasmine.Env() required');
+  }
+  if (!suite) {
+    throw new Error('jasmine.Suite() required');
+  }
+  var spec = this;
+  spec.id = env.nextSpecId ? env.nextSpecId() : null;
+  spec.env = env;
+  spec.suite = suite;
+  spec.description = description;
+  spec.queue = new jasmine.Queue(env);
+
+  spec.afterCallbacks = [];
+  spec.spies_ = [];
+
+  spec.results_ = new jasmine.NestedResults();
+  spec.results_.description = description;
+  spec.matchersClass = null;
+};
+
+jasmine.Spec.prototype.getFullName = function() {
+  return this.suite.getFullName() + ' ' + this.description + '.';
+};
+
+
+jasmine.Spec.prototype.results = function() {
+  return this.results_;
+};
+
+/**
+ * All parameters are pretty-printed and concatenated together, then written to the spec's output.
+ *
+ * Be careful not to leave calls to <code>jasmine.log</code> in production code.
+ */
+jasmine.Spec.prototype.log = function() {
+  return this.results_.log(arguments);
+};
+
+jasmine.Spec.prototype.runs = function (func) {
+  var block = new jasmine.Block(this.env, func, this);
+  this.addToQueue(block);
+  return this;
+};
+
+jasmine.Spec.prototype.addToQueue = function (block) {
+  if (this.queue.isRunning()) {
+    this.queue.insertNext(block);
+  } else {
+    this.queue.add(block);
+  }
+};
+
+/**
+ * @param {jasmine.ExpectationResult} result
+ */
+jasmine.Spec.prototype.addMatcherResult = function(result) {
+  this.results_.addResult(result);
+};
+
+jasmine.Spec.prototype.expect = function(actual) {
+  var positive = new (this.getMatchersClass_())(this.env, actual, this);
+  positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
+  return positive;
+};
+
+/**
+ * Waits a fixed time period before moving to the next block.
+ *
+ * @deprecated Use waitsFor() instead
+ * @param {Number} timeout milliseconds to wait
+ */
+jasmine.Spec.prototype.waits = function(timeout) {
+  var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
+  this.addToQueue(waitsFunc);
+  return this;
+};
+
+/**
+ * Waits for the latchFunction to return true before proceeding to the next block.
+ *
+ * @param {Function} latchFunction
+ * @param {String} optional_timeoutMessage
+ * @param {Number} optional_timeout
+ */
+jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
+  var latchFunction_ = null;
+  var optional_timeoutMessage_ = null;
+  var optional_timeout_ = null;
+
+  for (var i = 0; i < arguments.length; i++) {
+    var arg = arguments[i];
+    switch (typeof arg) {
+      case 'function':
+        latchFunction_ = arg;
+        break;
+      case 'string':
+        optional_timeoutMessage_ = arg;
+        break;
+      case 'number':
+        optional_timeout_ = arg;
+        break;
+    }
+  }
+
+  var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
+  this.addToQueue(waitsForFunc);
+  return this;
+};
+
+jasmine.Spec.prototype.fail = function (e) {
+  var expectationResult = new jasmine.ExpectationResult({
+    passed: false,
+    message: e ? jasmine.util.formatException(e) : 'Exception',
+    trace: { stack: e.stack }
+  });
+  this.results_.addResult(expectationResult);
+};
+
+jasmine.Spec.prototype.getMatchersClass_ = function() {
+  return this.matchersClass || this.env.matchersClass;
+};
+
+jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
+  var parent = this.getMatchersClass_();
+  var newMatchersClass = function() {
+    parent.apply(this, arguments);
+  };
+  jasmine.util.inherit(newMatchersClass, parent);
+  jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
+  this.matchersClass = newMatchersClass;
+};
+
+jasmine.Spec.prototype.finishCallback = function() {
+  this.env.reporter.reportSpecResults(this);
+};
+
+jasmine.Spec.prototype.finish = function(onComplete) {
+  this.removeAllSpies();
+  this.finishCallback();
+  if (onComplete) {
+    onComplete();
+  }
+};
+
+jasmine.Spec.prototype.after = function(doAfter) {
+  if (this.queue.isRunning()) {
+    this.queue.add(new jasmine.Block(this.env, doAfter, this));
+  } else {
+    this.afterCallbacks.unshift(doAfter);
+  }
+};
+
+jasmine.Spec.prototype.execute = function(onComplete) {
+  var spec = this;
+  if (!spec.env.specFilter(spec)) {
+    spec.results_.skipped = true;
+    spec.finish(onComplete);
+    return;
+  }
+
+  this.env.reporter.reportSpecStarting(this);
+
+  spec.env.currentSpec = spec;
+
+  spec.addBeforesAndAftersToQueue();
+
+  spec.queue.start(function () {
+    spec.finish(onComplete);
+  });
+};
+
+jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
+  var runner = this.env.currentRunner();
+  var i;
+
+  for (var suite = this.suite; suite; suite = suite.parentSuite) {
+    for (i = 0; i < suite.before_.length; i++) {
+      this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
+    }
+  }
+  for (i = 0; i < runner.before_.length; i++) {
+    this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
+  }
+  for (i = 0; i < this.afterCallbacks.length; i++) {
+    this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));
+  }
+  for (suite = this.suite; suite; suite = suite.parentSuite) {
+    for (i = 0; i < suite.after_.length; i++) {
+      this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));
+    }
+  }
+  for (i = 0; i < runner.after_.length; i++) {
+    this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
+  }
+};
+
+jasmine.Spec.prototype.explodes = function() {
+  throw 'explodes function should not have been called';
+};
+
+jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
+  if (obj == jasmine.undefined) {
+    throw "spyOn could not find an object to spy upon for " + methodName + "()";
+  }
+
+  if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
+    throw methodName + '() method does not exist';
+  }
+
+  if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
+    throw new Error(methodName + ' has already been spied upon');
+  }
+
+  var spyObj = jasmine.createSpy(methodName);
+
+  this.spies_.push(spyObj);
+  spyObj.baseObj = obj;
+  spyObj.methodName = methodName;
+  spyObj.originalValue = obj[methodName];
+
+  obj[methodName] = spyObj;
+
+  return spyObj;
+};
+
+jasmine.Spec.prototype.removeAllSpies = function() {
+  for (var i = 0; i < this.spies_.length; i++) {
+    var spy = this.spies_[i];
+    spy.baseObj[spy.methodName] = spy.originalValue;
+  }
+  this.spies_ = [];
+};
+
+/**
+ * Internal representation of a Jasmine suite.
+ *
+ * @constructor
+ * @param {jasmine.Env} env
+ * @param {String} description
+ * @param {Function} specDefinitions
+ * @param {jasmine.Suite} parentSuite
+ */
+jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
+  var self = this;
+  self.id = env.nextSuiteId ? env.nextSuiteId() : null;
+  self.description = description;
+  self.queue = new jasmine.Queue(env);
+  self.parentSuite = parentSuite;
+  self.env = env;
+  self.before_ = [];
+  self.after_ = [];
+  self.children_ = [];
+  self.suites_ = [];
+  self.specs_ = [];
+};
+
+jasmine.Suite.prototype.getFullName = function() {
+  var fullName = this.description;
+  for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
+    fullName = parentSuite.description + ' ' + fullName;
+  }
+  return fullName;
+};
+
+jasmine.Suite.prototype.finish = function(onComplete) {
+  this.env.reporter.reportSuiteResults(this);
+  this.finished = true;
+  if (typeof(onComplete) == 'function') {
+    onComplete();
+  }
+};
+
+jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
+  beforeEachFunction.typeName = 'beforeEach';
+  this.before_.unshift(beforeEachFunction);
+};
+
+jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
+  afterEachFunction.typeName = 'afterEach';
+  this.after_.unshift(afterEachFunction);
+};
+
+jasmine.Suite.prototype.results = function() {
+  return this.queue.results();
+};
+
+jasmine.Suite.prototype.add = function(suiteOrSpec) {
+  this.children_.push(suiteOrSpec);
+  if (suiteOrSpec instanceof jasmine.Suite) {
+    this.suites_.push(suiteOrSpec);
+    this.env.currentRunner().addSuite(suiteOrSpec);
+  } else {
+    this.specs_.push(suiteOrSpec);
+  }
+  this.queue.add(suiteOrSpec);
+};
+
+jasmine.Suite.prototype.specs = function() {
+  return this.specs_;
+};
+
+jasmine.Suite.prototype.suites = function() {
+  return this.suites_;
+};
+
+jasmine.Suite.prototype.children = function() {
+  return this.children_;
+};
+
+jasmine.Suite.prototype.execute = function(onComplete) {
+  var self = this;
+  this.queue.start(function () {
+    self.finish(onComplete);
+  });
+};
+jasmine.WaitsBlock = function(env, timeout, spec) {
+  this.timeout = timeout;
+  jasmine.Block.call(this, env, null, spec);
+};
+
+jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
+
+jasmine.WaitsBlock.prototype.execute = function (onComplete) {
+  if (jasmine.VERBOSE) {
+    this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
+  }
+  this.env.setTimeout(function () {
+    onComplete();
+  }, this.timeout);
+};
+/**
+ * A block which waits for some condition to become true, with timeout.
+ *
+ * @constructor
+ * @extends jasmine.Block
+ * @param {jasmine.Env} env The Jasmine environment.
+ * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
+ * @param {Function} latchFunction A function which returns true when the desired condition has been met.
+ * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
+ * @param {jasmine.Spec} spec The Jasmine spec.
+ */
+jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
+  this.timeout = timeout || env.defaultTimeoutInterval;
+  this.latchFunction = latchFunction;
+  this.message = message;
+  this.totalTimeSpentWaitingForLatch = 0;
+  jasmine.Block.call(this, env, null, spec);
+};
+jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
+
+jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
+
+jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
+  if (jasmine.VERBOSE) {
+    this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
+  }
+  var latchFunctionResult;
+  try {
+    latchFunctionResult = this.latchFunction.apply(this.spec);
+  } catch (e) {
+    this.spec.fail(e);
+    onComplete();
+    return;
+  }
+
+  if (latchFunctionResult) {
+    onComplete();
+  } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
+    var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
+    this.spec.fail({
+      name: 'timeout',
+      message: message
+    });
+
+    this.abort = true;
+    onComplete();
+  } else {
+    this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
+    var self = this;
+    this.env.setTimeout(function() {
+      self.execute(onComplete);
+    }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
+  }
+};
+
+jasmine.version_= {
+  "major": 1,
+  "minor": 2,
+  "build": 0,
+  "revision": 1337005947
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/config.xml
----------------------------------------------------------------------
diff --git a/templates/www/config.xml b/templates/www/config.xml
deleted file mode 100644
index 206bc56..0000000
--- a/templates/www/config.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<widget xmlns     = "http://www.w3.org/ns/widgets"
-        xmlns:gap = "http://phonegap.com/ns/1.0"
-        id        = "io.cordova.hello-cordova"
-        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="callback-dev@incubator.apache.org">
-        Apache Cordova Team
-    </author>
-
-    <icon src="res/icon/cordova_512.png"        width="512" height="512" />
-    <icon src="res/icon/cordova_android_96.png" width="96"  height="96"  gap:platform="android" />
-    <icon src="res/icon/cordova_bb_80.png"      width="80"  height="80"  gap:platform="blackberry" />
-    <icon src="res/icon/cordova_ios_144.png"    width="144" height="144" gap:platform="ios" />
-
-    <gap:splash src="res/screen/android_hdpi_landscape.png"      width="800"  height="480"  gap:platform="android" />
-    <gap:splash src="res/screen/android_hdpi_portrait.png"       width="480"  height="800"  gap:platform="android" />
-    <gap:splash src="res/screen/android_ldpi_landscape.png"      width="320"  height="200"  gap:platform="android" />
-    <gap:splash src="res/screen/android_ldpi_portrait.png"       width="200"  height="320"  gap:platform="android" />
-    <gap:splash src="res/screen/android_mdpi_landscape.png"      width="480"  height="320"  gap:platform="android" />
-    <gap:splash src="res/screen/android_mdpi_portrait.png"       width="320"  height="480"  gap:platform="android" />
-    <gap:splash src="res/screen/android_xhdpi_landscape.png"     width="1280" height="720"  gap:platform="android" />
-    <gap:splash src="res/screen/android_xhdpi_portrait.png"      width="720"  height="1280" gap:platform="android" />
-    <gap:splash src="res/screen/blackberry_transparent_300.png"  width="300"  height="300"  gap:platform="blackberry" />
-    <gap:splash src="res/screen/blackberry_transparent_400.png"  width="200"  height="200"  gap:platform="blackberry" />
-    <gap:splash src="res/screen/ipad_landscape.png"              width="1024" height="748"  gap:platform="ios" />
-    <gap:splash src="res/screen/ipad_portrait.png"               width="768"  height="1004" gap:platform="ios" />
-    <gap:splash src="res/screen/ipad_retina_landscape.png"       width="2048" height="1496" gap:platform="ios" />
-    <gap:splash src="res/screen/ipad_retina_portrait.png"        width="1536" height="2008" gap:platform="ios" />
-    <gap:splash src="res/screen/iphone_landscape.png"            width="480"  height="320"  gap:platform="ios" />
-    <gap:splash src="res/screen/iphone_portrait.png"             width="320"  height="480"  gap:platform="ios" />
-    <gap:splash src="res/screen/iphone_retina_landscape.png"     width="960"  height="640"  gap:platform="ios" />
-    <gap:splash src="res/screen/iphone_retina_portrait.png"      width="640"  height="960"  gap:platform="ios" />
-    <gap:splash src="res/screen/windows_phone_portrait.jpg"      width="480"  height="800"  gap:platform="winphone" />
-
-    <feature name="http://api.phonegap.com/1.0/device" />
-
-    <preference name="phonegap-version" value="1.9.0" />
-    <preference name="orientation"      value="default" />
-    <preference name="target-device"    value="universal" />
-    <preference name="fullscreen"       value="false" />
-
-    <access origin="*" />
-</widget>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/css/index.css
----------------------------------------------------------------------
diff --git a/templates/www/css/index.css b/templates/www/css/index.css
deleted file mode 100644
index c869f87..0000000
--- a/templates/www/css/index.css
+++ /dev/null
@@ -1,100 +0,0 @@
-html,
-body {
-    height:100%;
-    font-size:12px;
-    width:100%;
-}
-
-html {
-    display:table;
-}
-
-body {
-    background-color:#A7A7A7;
-    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)
-    );
-    display:table-cell;
-    font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
-    text-transform:uppercase;
-    vertical-align:middle;
-}
-
-.app {
-    background-image:url(../img/cordova.png);
-    background-repeat:no-repeat;
-    margin:0px auto;
-    width:275px;
-}
-
-h1 {
-    font-size:2em;
-    font-weight:300;
-    margin:0px;
-    overflow:visible;
-    padding:0px;
-    text-align:center;
-}
-
-.status {
-    background-color:#333333;
-    border-radius:4px;
-    -webkit-border-radius:4px;
-    color:#FFFFFF;
-    font-size:1em;
-    margin:0px auto;
-    padding:2px 10px;
-    text-align:center;
-    width:100%;
-    max-width:175px;
-}
-
-.status.complete {
-    background-color:#4B946A;
-}
-
-.hide {
-    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;
-}
-
-/* portrait */
-/* @media screen and (max-aspect-ratio: 1/1) */
-.app {
-    background-position:center top;
-    height:100px;              /* adds enough room for text */
-    padding:180px 0px 0px 0px; /* background height - shadow offset */
-}
-
-/* lanscape (when wide enough) */
-@media screen and (min-aspect-ratio: 1/1) and (min-width:445px) {
-    .app {
-        background-position:left center;
-        height:140px;       /* height + padding = background image size */
-        padding-left:170px; /* background width */
-        padding-top:60px;   /* center the text */
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/img/cordova.png
----------------------------------------------------------------------
diff --git a/templates/www/img/cordova.png b/templates/www/img/cordova.png
deleted file mode 100644
index e8169cf..0000000
Binary files a/templates/www/img/cordova.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/index.html
----------------------------------------------------------------------
diff --git a/templates/www/index.html b/templates/www/index.html
deleted file mode 100644
index 202af51..0000000
--- a/templates/www/index.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-        <meta name = "format-detection" content = "telephone=no"/>
-        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width;" />
-        <link rel="stylesheet" type="text/css" href="css/index.css" />
-        <title>Hello Cordova</title>
-    </head>
-    <body>
-        <div class="app">
-            <h1>Apache Cordova</h1>
-            <div id="deviceready">
-                <p class="status pending blink">Connecting to Device</p>
-                <p class="status complete blink hide">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/740ff28d/templates/www/js/index.js
----------------------------------------------------------------------
diff --git a/templates/www/js/index.js b/templates/www/js/index.js
deleted file mode 100644
index 6140331..0000000
--- a/templates/www/js/index.js
+++ /dev/null
@@ -1,20 +0,0 @@
-var app = {
-    initialize: function() {
-        this.bind();
-    },
-    bind: function() {
-        document.addEventListener('deviceready', this.deviceready, false);
-    },
-    deviceready: function() {
-        // note that this is an event handler so the scope is that of the event
-        // so we need to call app.report(), and not this.report()
-        app.report('deviceready');
-    },
-    report: function(id) { 
-        console.log("report:" + id);
-        // hide the .pending <p> and show the .complete <p>
-        document.querySelector('#' + id + ' .pending').className += ' hide';
-        var completeElem = document.querySelector('#' + id + ' .complete');
-        completeElem.className = completeElem.className.split('hide').join('');
-    }
-};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/icon/cordova_128.png
----------------------------------------------------------------------
diff --git a/templates/www/res/icon/cordova_128.png b/templates/www/res/icon/cordova_128.png
deleted file mode 100644
index 3516df3..0000000
Binary files a/templates/www/res/icon/cordova_128.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/icon/cordova_16.png
----------------------------------------------------------------------
diff --git a/templates/www/res/icon/cordova_16.png b/templates/www/res/icon/cordova_16.png
deleted file mode 100644
index 54e19c5..0000000
Binary files a/templates/www/res/icon/cordova_16.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/icon/cordova_24.png
----------------------------------------------------------------------
diff --git a/templates/www/res/icon/cordova_24.png b/templates/www/res/icon/cordova_24.png
deleted file mode 100644
index c7d43ad..0000000
Binary files a/templates/www/res/icon/cordova_24.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/icon/cordova_256.png
----------------------------------------------------------------------
diff --git a/templates/www/res/icon/cordova_256.png b/templates/www/res/icon/cordova_256.png
deleted file mode 100644
index e1cd0e6..0000000
Binary files a/templates/www/res/icon/cordova_256.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/icon/cordova_32.png
----------------------------------------------------------------------
diff --git a/templates/www/res/icon/cordova_32.png b/templates/www/res/icon/cordova_32.png
deleted file mode 100644
index 734fffc..0000000
Binary files a/templates/www/res/icon/cordova_32.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/icon/cordova_48.png
----------------------------------------------------------------------
diff --git a/templates/www/res/icon/cordova_48.png b/templates/www/res/icon/cordova_48.png
deleted file mode 100644
index 8ad8bac..0000000
Binary files a/templates/www/res/icon/cordova_48.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/icon/cordova_512.png
----------------------------------------------------------------------
diff --git a/templates/www/res/icon/cordova_512.png b/templates/www/res/icon/cordova_512.png
deleted file mode 100644
index c9465f3..0000000
Binary files a/templates/www/res/icon/cordova_512.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/icon/cordova_64.png
----------------------------------------------------------------------
diff --git a/templates/www/res/icon/cordova_64.png b/templates/www/res/icon/cordova_64.png
deleted file mode 100644
index 03b3849..0000000
Binary files a/templates/www/res/icon/cordova_64.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/icon/cordova_android_36.png
----------------------------------------------------------------------
diff --git a/templates/www/res/icon/cordova_android_36.png b/templates/www/res/icon/cordova_android_36.png
deleted file mode 100644
index cd5032a..0000000
Binary files a/templates/www/res/icon/cordova_android_36.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/icon/cordova_android_48.png
----------------------------------------------------------------------
diff --git a/templates/www/res/icon/cordova_android_48.png b/templates/www/res/icon/cordova_android_48.png
deleted file mode 100644
index e79c606..0000000
Binary files a/templates/www/res/icon/cordova_android_48.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/icon/cordova_android_72.png
----------------------------------------------------------------------
diff --git a/templates/www/res/icon/cordova_android_72.png b/templates/www/res/icon/cordova_android_72.png
deleted file mode 100644
index 4d27634..0000000
Binary files a/templates/www/res/icon/cordova_android_72.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/icon/cordova_android_96.png
----------------------------------------------------------------------
diff --git a/templates/www/res/icon/cordova_android_96.png b/templates/www/res/icon/cordova_android_96.png
deleted file mode 100644
index ec7ffbf..0000000
Binary files a/templates/www/res/icon/cordova_android_96.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/icon/cordova_bb_80.png
----------------------------------------------------------------------
diff --git a/templates/www/res/icon/cordova_bb_80.png b/templates/www/res/icon/cordova_bb_80.png
deleted file mode 100644
index f86a27a..0000000
Binary files a/templates/www/res/icon/cordova_bb_80.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/icon/cordova_ios_114.png
----------------------------------------------------------------------
diff --git a/templates/www/res/icon/cordova_ios_114.png b/templates/www/res/icon/cordova_ios_114.png
deleted file mode 100644
index efd9c37..0000000
Binary files a/templates/www/res/icon/cordova_ios_114.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/icon/cordova_ios_144.png
----------------------------------------------------------------------
diff --git a/templates/www/res/icon/cordova_ios_144.png b/templates/www/res/icon/cordova_ios_144.png
deleted file mode 100644
index dd819da..0000000
Binary files a/templates/www/res/icon/cordova_ios_144.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/icon/cordova_ios_57.png
----------------------------------------------------------------------
diff --git a/templates/www/res/icon/cordova_ios_57.png b/templates/www/res/icon/cordova_ios_57.png
deleted file mode 100644
index c795fc4..0000000
Binary files a/templates/www/res/icon/cordova_ios_57.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/icon/cordova_ios_72.png
----------------------------------------------------------------------
diff --git a/templates/www/res/icon/cordova_ios_72.png b/templates/www/res/icon/cordova_ios_72.png
deleted file mode 100644
index b1cfde7..0000000
Binary files a/templates/www/res/icon/cordova_ios_72.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/android_hdpi_landscape.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/android_hdpi_landscape.png b/templates/www/res/screen/android_hdpi_landscape.png
deleted file mode 100644
index a61e2b1..0000000
Binary files a/templates/www/res/screen/android_hdpi_landscape.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/android_hdpi_portrait.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/android_hdpi_portrait.png b/templates/www/res/screen/android_hdpi_portrait.png
deleted file mode 100644
index 5d6a28a..0000000
Binary files a/templates/www/res/screen/android_hdpi_portrait.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/android_ldpi_landscape.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/android_ldpi_landscape.png b/templates/www/res/screen/android_ldpi_landscape.png
deleted file mode 100644
index f3934cd..0000000
Binary files a/templates/www/res/screen/android_ldpi_landscape.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/android_ldpi_portrait.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/android_ldpi_portrait.png b/templates/www/res/screen/android_ldpi_portrait.png
deleted file mode 100644
index 65ad163..0000000
Binary files a/templates/www/res/screen/android_ldpi_portrait.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/android_mdpi_landscape.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/android_mdpi_landscape.png b/templates/www/res/screen/android_mdpi_landscape.png
deleted file mode 100644
index a1b697c..0000000
Binary files a/templates/www/res/screen/android_mdpi_landscape.png and /dev/null differ


[05/43] git commit: No tags for JS-only plugins.

Posted by an...@apache.org.
No <platform> tags for JS-only plugins.


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

Branch: refs/heads/master
Commit: 19d696600aceb750c4d534f28b36b3494dd6b789
Parents: 10ad93d
Author: Braden Shepherdson <br...@gmail.com>
Authored: Tue Mar 26 16:40:31 2013 -0400
Committer: Braden Shepherdson <br...@gmail.com>
Committed: Tue Mar 26 16:40:31 2013 -0400

----------------------------------------------------------------------
 src/plugin.js |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/19d69660/src/plugin.js
----------------------------------------------------------------------
diff --git a/src/plugin.js b/src/plugin.js
index f2638f5..bbe04b3 100644
--- a/src/plugin.js
+++ b/src/plugin.js
@@ -121,8 +121,10 @@ module.exports = function plugin(command, targets, callback) {
                         else return true;
                     });
 
-                    // Iterate over all matchin app-plugin platforms in the project and uninstall the
-                    // plugin.
+                    // Iterate over all the common platforms between the plugin
+                    // and the app, and uninstall.
+                    // If this is a web-only plugin with no platform tags, this step
+                    // is not needed and we just --remove the plugin below.
                     var cmd;
                     intersection.forEach(function(platform) {
                         cmd = util.format('%s --platform %s --project "%s" --plugin "%s" --plugins_dir "%s" --uninstall', cli, platform, path.join(projectRoot, 'platforms', platform), targetName, path.join(projectRoot, 'plugins'));


[23/43] 2.6.0rc1 used for libs now. Bumped npm version to 2.6.0. added androids local.properties to gitignore.

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebViewClient.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebViewClient.java b/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebViewClient.java
index 8b023eb..4751fc3 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebViewClient.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebViewClient.java
@@ -18,6 +18,7 @@
 */
 package org.apache.cordova;
 
+import java.io.ByteArrayInputStream;
 import java.util.Hashtable;
 
 import org.apache.cordova.api.CordovaInterface;
@@ -38,6 +39,7 @@ import android.util.Log;
 import android.view.View;
 import android.webkit.HttpAuthHandler;
 import android.webkit.SslErrorHandler;
+import android.webkit.WebResourceResponse;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
 
@@ -66,7 +68,7 @@ public class CordovaWebViewClient extends WebViewClient {
 
     /**
      * Constructor.
-     * 
+     *
      * @param cordova
      * @param view
      */
@@ -77,7 +79,7 @@ public class CordovaWebViewClient extends WebViewClient {
 
     /**
      * Constructor.
-     * 
+     *
      * @param view
      */
     public void setWebView(CordovaWebView view) {
@@ -101,8 +103,8 @@ public class CordovaWebViewClient extends WebViewClient {
 		String callbackId = url.substring(idx3 + 1, idx4);
 		String jsonArgs   = url.substring(idx4 + 1);
         appView.pluginManager.exec(service, action, callbackId, jsonArgs);
-	}    
-	
+	}
+
     /**
      * Give the host application a chance to take over the control when a new url
      * is about to be loaded in the current WebView.
@@ -192,12 +194,8 @@ public class CordovaWebViewClient extends WebViewClient {
 
             // If our app or file:, then load into a new Cordova webview container by starting a new instance of our activity.
             // Our app continues to run.  When BACK is pressed, our app is redisplayed.
-            if (url.startsWith("file://") || url.startsWith("data:") || url.indexOf(this.appView.baseUrl) == 0 || Config.isUrlWhiteListed(url)) {
-                //This will fix iFrames
-                if (appView.useBrowserHistory || url.startsWith("data:"))
-                    return false;
-                else
-                    this.appView.loadUrl(url);
+            if (url.startsWith("file://") || url.startsWith("data:")  || Config.isUrlWhiteListed(url)) {
+                return false;
             }
 
             // If not our application, let default viewer handle
@@ -215,6 +213,34 @@ public class CordovaWebViewClient extends WebViewClient {
     }
 
     /**
+     * Check for intercepting any requests for resources.
+     * This includes images and scripts and so on, not just top-level pages.
+     * @param view          The WebView.
+     * @param url           The URL to be loaded.
+     * @return              Either null to proceed as normal, or a WebResourceResponse.
+     */
+    @Override
+    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
+      //If something isn't whitelisted, just send a blank response
+        if(!Config.isUrlWhiteListed(url) && (url.startsWith("http://") || url.startsWith("https://")))
+        {
+            return getWhitelistResponse();
+        }
+    	if (this.appView.pluginManager != null) {
+            return this.appView.pluginManager.shouldInterceptRequest(url);
+        }
+        return null;
+    }
+    
+    private WebResourceResponse getWhitelistResponse()
+    {
+        WebResourceResponse emptyResponse;
+        String empty = "";
+        ByteArrayInputStream data = new ByteArrayInputStream(empty.getBytes());
+        return new WebResourceResponse("text/plain", "UTF-8", data);
+    }
+
+    /**
      * On received http auth request.
      * The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination
      *
@@ -230,7 +256,7 @@ public class CordovaWebViewClient extends WebViewClient {
         AuthenticationToken token = this.getAuthenticationToken(host, realm);
         if (token != null) {
             handler.proceed(token.getUserName(), token.getPassword());
-        } 
+        }
         else {
             // Handle 401 like we'd normally do!
             super.onReceivedHttpAuthRequest(view, handler, host, realm);
@@ -238,22 +264,16 @@ public class CordovaWebViewClient extends WebViewClient {
     }
 
     /**
-     * Notify the host application that a page has started loading. 
-     * This method is called once for each main frame load so a page with iframes or framesets will call onPageStarted 
-     * one time for the main frame. This also means that onPageStarted will not be called when the contents of an 
-     * embedded frame changes, i.e. clicking a link whose target is an iframe. 
-     * 
+     * Notify the host application that a page has started loading.
+     * This method is called once for each main frame load so a page with iframes or framesets will call onPageStarted
+     * one time for the main frame. This also means that onPageStarted will not be called when the contents of an
+     * embedded frame changes, i.e. clicking a link whose target is an iframe.
+     *
      * @param view          The webview initiating the callback.
      * @param url           The url of the page.
      */
     @Override
     public void onPageStarted(WebView view, String url, Bitmap favicon) {
-        // Clear history so history.back() doesn't do anything.
-        // So we can reinit() native side CallbackServer & PluginManager.
-        if (!this.appView.useBrowserHistory) {
-            view.clearHistory();
-            this.doClearHistory = true;
-        }
 
         // Flush stale messages.
         this.appView.jsMessageQueue.reset();
@@ -270,7 +290,7 @@ public class CordovaWebViewClient extends WebViewClient {
     /**
      * Notify the host application that a page has finished loading.
      * This method is called only for main frame. When onPageFinished() is called, the rendering picture may not be updated yet.
-     * 
+     *
      *
      * @param view          The webview initiating the callback.
      * @param url           The url of the page.
@@ -359,11 +379,11 @@ public class CordovaWebViewClient extends WebViewClient {
     }
 
     /**
-     * Notify the host application that an SSL error occurred while loading a resource. 
-     * The host application must call either handler.cancel() or handler.proceed(). 
-     * Note that the decision may be retained for use in response to future SSL errors. 
+     * Notify the host application that an SSL error occurred while loading a resource.
+     * The host application must call either handler.cancel() or handler.proceed().
+     * Note that the decision may be retained for use in response to future SSL errors.
      * The default behavior is to cancel the load.
-     * 
+     *
      * @param view          The WebView that is initiating the callback.
      * @param handler       An SslErrorHandler object that will handle the user's response.
      * @param error         The SSL error object.
@@ -392,27 +412,10 @@ public class CordovaWebViewClient extends WebViewClient {
         }
     }
 
-    /**
-     * Notify the host application to update its visited links database.
-     * 
-     * @param view          The WebView that is initiating the callback.
-     * @param url           The url being visited.
-     * @param isReload      True if this url is being reloaded.
-     */
-    @Override
-    public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {
-        /*
-         * If you do a document.location.href the url does not get pushed on the stack
-         * so we do a check here to see if the url should be pushed.
-         */
-        if (!this.appView.peekAtUrlStack().equals(url)) {
-            this.appView.pushUrl(url);
-        }
-    }
 
     /**
      * Sets the authentication token.
-     * 
+     *
      * @param authenticationToken
      * @param host
      * @param realm
@@ -429,10 +432,10 @@ public class CordovaWebViewClient extends WebViewClient {
 
     /**
      * Removes the authentication token.
-     * 
+     *
      * @param host
      * @param realm
-     * 
+     *
      * @return the authentication token or null if did not exist
      */
     public AuthenticationToken removeAuthenticationToken(String host, String realm) {
@@ -441,16 +444,16 @@ public class CordovaWebViewClient extends WebViewClient {
 
     /**
      * Gets the authentication token.
-     * 
+     *
      * In order it tries:
      * 1- host + realm
      * 2- host
      * 3- realm
      * 4- no host, no realm
-     * 
+     *
      * @param host
      * @param realm
-     * 
+     *
      * @return the authentication token
      */
     public AuthenticationToken getAuthenticationToken(String host, String realm) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/Device.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/Device.java b/lib/cordova-android/framework/src/org/apache/cordova/Device.java
index 5b09c13..ad399f0 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/Device.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/Device.java
@@ -38,7 +38,7 @@ import android.telephony.TelephonyManager;
 public class Device extends CordovaPlugin {
     public static final String TAG = "Device";
 
-    public static String cordovaVersion = "2.5.0";              // Cordova version
+    public static String cordovaVersion = "2.6.0rc1";              // Cordova version
     public static String platform = "Android";                  // Device OS
     public static String uuid;                                  // Device UUID
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/DroidGap.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/DroidGap.java b/lib/cordova-android/framework/src/org/apache/cordova/DroidGap.java
index 9a7be4e..d4296cb 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/DroidGap.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/DroidGap.java
@@ -28,6 +28,7 @@ import org.apache.cordova.api.LOG;
 import org.json.JSONException;
 import org.json.JSONObject;
 
+import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -332,6 +333,7 @@ public class DroidGap extends Activity implements CordovaInterface {
      * @param webViewClient
      * @param webChromeClient
      */
+    @SuppressLint("NewApi")
     public void init(CordovaWebView webView, CordovaWebViewClient webViewClient, CordovaChromeClient webChromeClient) {
         LOG.d(TAG, "DroidGap.init()");
 
@@ -349,6 +351,12 @@ public class DroidGap extends Activity implements CordovaInterface {
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 1.0F));
 
+        if (this.getBooleanProperty("disallowOverscroll", false)) {
+            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD) {
+                this.appView.setOverScrollMode(CordovaWebView.OVER_SCROLL_NEVER);
+            }
+        }
+
         // Add web view but make it invisible while loading URL
         this.appView.setVisibility(View.INVISIBLE);
         this.root.addView(this.appView);
@@ -1054,7 +1062,8 @@ public class DroidGap extends Activity implements CordovaInterface {
     {
         //Get whatever has focus!
         View childView = appView.getFocusedChild();
-        if ((appView.isCustomViewShowing() || childView != null ) && keyCode == KeyEvent.KEYCODE_BACK) {
+        if ((appView.isCustomViewShowing() || childView != null ) &&
+                (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU)) {
             return appView.onKeyUp(keyCode, event);
         } else {
             return super.onKeyUp(keyCode, event);
@@ -1074,7 +1083,7 @@ public class DroidGap extends Activity implements CordovaInterface {
         //Get whatever has focus!
         View childView = appView.getFocusedChild();
         //Determine if the focus is on the current view or not
-        if (childView != null && keyCode == KeyEvent.KEYCODE_BACK) {
+        if (childView != null && (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU)) {
                     return appView.onKeyDown(keyCode, event);
         }
         else

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/FileHelper.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/FileHelper.java b/lib/cordova-android/framework/src/org/apache/cordova/FileHelper.java
new file mode 100644
index 0000000..c10ed96
--- /dev/null
+++ b/lib/cordova-android/framework/src/org/apache/cordova/FileHelper.java
@@ -0,0 +1,142 @@
+/*
+       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.apache.cordova;
+
+import android.database.Cursor;
+import android.net.Uri;
+import android.webkit.MimeTypeMap;
+
+import org.apache.cordova.api.CordovaInterface;
+import org.apache.cordova.api.LOG;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class FileHelper {
+    private static final String LOG_TAG = "FileUtils";
+    private static final String _DATA = "_data";
+
+    /**
+     * Returns the real path of the given URI string.
+     * If the given URI string represents a content:// URI, the real path is retrieved from the media store.
+     *
+     * @param uriString the URI string of the audio/image/video
+     * @param cordova the current application context
+     * @return the full path to the file
+     */
+    @SuppressWarnings("deprecation")
+    public static String getRealPath(String uriString, CordovaInterface cordova) {
+        String realPath = null;
+
+        if (uriString.startsWith("content://")) {
+            String[] proj = { _DATA };
+            Cursor cursor = cordova.getActivity().managedQuery(Uri.parse(uriString), proj, null, null, null);
+            int column_index = cursor.getColumnIndexOrThrow(_DATA);
+            cursor.moveToFirst();
+            realPath = cursor.getString(column_index);
+            if (realPath == null) {
+                LOG.e(LOG_TAG, "Could get real path for URI string %s", uriString);
+            }
+        } else if (uriString.startsWith("file://")) {
+            realPath = uriString.substring(7);
+            if (realPath.startsWith("/android_asset/")) {
+                LOG.e(LOG_TAG, "Cannot get real path for URI string %s because it is a file:///android_asset/ URI.", uriString);
+                realPath = null;
+            }
+        } else {
+            realPath = uriString;
+        }
+
+        return realPath;
+    }
+
+    /**
+     * Returns the real path of the given URI.
+     * If the given URI is a content:// URI, the real path is retrieved from the media store.
+     *
+     * @param uri the URI of the audio/image/video
+     * @param cordova the current application context
+     * @return the full path to the file
+     */
+    public static String getRealPath(Uri uri, CordovaInterface cordova) {
+        return FileHelper.getRealPath(uri.toString(), cordova);
+    }
+
+    /**
+     * Returns an input stream based on given URI string.
+     *
+     * @param uriString the URI string from which to obtain the input stream
+     * @param cordova the current application context
+     * @return an input stream into the data at the given URI or null if given an invalid URI string
+     * @throws IOException
+     */
+    public static InputStream getInputStreamFromUriString(String uriString, CordovaInterface cordova) throws IOException {
+        if (uriString.startsWith("content")) {
+            Uri uri = Uri.parse(uriString);
+            return cordova.getActivity().getContentResolver().openInputStream(uri);
+        } else if (uriString.startsWith("file:///android_asset/")) {
+            String relativePath = uriString.substring(22);
+            return cordova.getActivity().getAssets().open(relativePath);
+        } else {
+            return new FileInputStream(getRealPath(uriString, cordova));
+        }
+    }
+
+    /**
+     * Removes the "file://" prefix from the given URI string, if applicable.
+     * If the given URI string doesn't have a "file://" prefix, it is returned unchanged.
+     *
+     * @param uriString the URI string to operate on
+     * @return a path without the "file://" prefix
+     */
+    public static String stripFileProtocol(String uriString) {
+        if (uriString.startsWith("file://")) {
+            uriString = uriString.substring(7);
+        }
+        return uriString;
+    }
+
+    /**
+     * Returns the mime type of the data specified by the given URI string.
+     *
+     * @param uriString the URI string of the data
+     * @return the mime type of the specified data
+     */
+    public static String getMimeType(String uriString, CordovaInterface cordova) {
+        String mimeType = null;
+
+        if (uriString.startsWith("content://")) {
+            Uri uri = Uri.parse(uriString);
+            mimeType = cordova.getActivity().getContentResolver().getType(uri);
+        } else {
+            // MimeTypeMap.getFileExtensionFromUrl has a bug that occurs when the filename has a space, so we encode it.
+            // We also convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
+            String encodedUriString = uriString.replace(" ", "%20").toLowerCase();
+            String extension = MimeTypeMap.getFileExtensionFromUrl(encodedUriString);
+            if (extension.equals("3ga")) {
+                mimeType = "audio/3gpp";
+            } else {
+                mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+            }
+        }
+
+        return mimeType;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java b/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java
index 623baf8..dba29af 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java
@@ -18,6 +18,7 @@
 */
 package org.apache.cordova;
 
+import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
 import java.io.File;
@@ -27,7 +28,9 @@ import java.io.FileOutputStream;
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.OutputStream;
+import java.io.StringWriter;
 import java.io.UnsupportedEncodingException;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
@@ -155,6 +158,25 @@ public class FileTransfer extends CordovaPlugin {
         return false;
     }
 
+    private static void addHeadersToRequest(URLConnection connection, JSONObject headers) {
+        try {
+            for (Iterator<?> iter = headers.keys(); iter.hasNext(); ) {
+                String headerKey = iter.next().toString();
+                JSONArray headerValues = headers.optJSONArray(headerKey);
+                if (headerValues == null) {
+                    headerValues = new JSONArray();
+                    headerValues.put(headers.getString(headerKey));
+                }
+                connection.setRequestProperty(headerKey, headerValues.getString(0));
+                for (int i = 1; i < headerValues.length(); ++i) {
+                    connection.addRequestProperty(headerKey, headerValues.getString(i));
+                }
+            }
+        } catch (JSONException e1) {
+          // No headers to be manipulated!
+        }
+    }
+
     /**
      * Uploads the specified file to the server URL provided using an HTTP multipart request.
      * @param source        Full path of the file on the file system
@@ -196,7 +218,7 @@ public class FileTransfer extends CordovaPlugin {
         try {
             url = new URL(target);
         } catch (MalformedURLException e) {
-            JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, 0);
+            JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, null, 0);
             Log.e(LOG_TAG, error.toString(), e);
             callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
             return;
@@ -269,22 +291,7 @@ public class FileTransfer extends CordovaPlugin {
 
                     // Handle the other headers
                     if (headers != null) {
-                        try {
-                            for (Iterator<?> iter = headers.keys(); iter.hasNext(); ) {
-                                String headerKey = iter.next().toString();
-                                JSONArray headerValues = headers.optJSONArray(headerKey);
-                                if (headerValues == null) {
-                                    headerValues = new JSONArray();
-                                    headerValues.put(headers.getString(headerKey));
-                                }
-                                conn.setRequestProperty(headerKey, headerValues.getString(0));
-                                for (int i = 1; i < headerValues.length(); ++i) {
-                                    conn.addRequestProperty(headerKey, headerValues.getString(i));
-                                }
-                            }
-                        } catch (JSONException e1) {
-                          // No headers to be manipulated!
-                        }
+                        addHeadersToRequest(conn, headers);
                     }
 
                     /*
@@ -530,18 +537,33 @@ public class FileTransfer extends CordovaPlugin {
     private static JSONObject createFileTransferError(int errorCode, String source, String target, URLConnection connection) {
 
         int httpStatus = 0;
-
+        StringBuilder bodyBuilder = new StringBuilder();
+        String body = null;
         if (connection != null) {
             try {
                 if (connection instanceof HttpURLConnection) {
                     httpStatus = ((HttpURLConnection)connection).getResponseCode();
+                    InputStream err = ((HttpURLConnection) connection).getErrorStream();
+                    if(err != null)
+                    {
+                        BufferedReader reader = new BufferedReader(new InputStreamReader(err, "UTF-8"));
+                        String line = reader.readLine();
+                        while(line != null)
+                        {
+                            bodyBuilder.append(line);
+                            line = reader.readLine();
+                            if(line != null)
+                                bodyBuilder.append('\n');
+                        }
+                        body = bodyBuilder.toString();
+                    }
                 }
             } catch (IOException e) {
                 Log.w(LOG_TAG, "Error getting HTTP status code from connection.", e);
             }
         }
 
-        return createFileTransferError(errorCode, source, target, httpStatus);
+        return createFileTransferError(errorCode, source, target, body, httpStatus);
     }
 
         /**
@@ -549,13 +571,17 @@ public class FileTransfer extends CordovaPlugin {
         * @param errorCode 	the error
         * @return JSONObject containing the error
         */
-    private static JSONObject createFileTransferError(int errorCode, String source, String target, Integer httpStatus) {
+    private static JSONObject createFileTransferError(int errorCode, String source, String target, String body, Integer httpStatus) {
         JSONObject error = null;
         try {
             error = new JSONObject();
             error.put("code", errorCode);
             error.put("source", source);
             error.put("target", target);
+            if(body != null)
+            {
+                error.put("body", body);
+            }   
             if (httpStatus != null) {
                 error.put("http_status", httpStatus);
             }
@@ -594,12 +620,13 @@ public class FileTransfer extends CordovaPlugin {
 
         final boolean trustEveryone = args.optBoolean(2);
         final String objectId = args.getString(3);
+        final JSONObject headers = args.optJSONObject(4);
 
         final URL url;
         try {
             url = new URL(source);
         } catch (MalformedURLException e) {
-            JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, 0);
+            JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, null, 0);
             Log.e(LOG_TAG, error.toString(), e);
             callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
             return;
@@ -608,7 +635,7 @@ public class FileTransfer extends CordovaPlugin {
 
         if (!Config.isUrlWhiteListed(source)) {
             Log.w(LOG_TAG, "Source URL is not in white list: '" + source + "'");
-            JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, 401);
+            JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, null, 401);
             callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
             return;
         }
@@ -671,6 +698,11 @@ public class FileTransfer extends CordovaPlugin {
                     {
                         connection.setRequestProperty("cookie", cookie);
                     }
+
+                    // Handle the other headers
+                    if (headers != null) {
+                        addHeadersToRequest(connection, headers);
+                    }
     
                     connection.connect();
     
@@ -718,8 +750,7 @@ public class FileTransfer extends CordovaPlugin {
                     Log.d(LOG_TAG, "Saved file: " + target);
     
                     // create FileEntry object
-                    FileUtils fileUtil = new FileUtils();
-                    JSONObject fileEntry = fileUtil.getEntry(file);
+                    JSONObject fileEntry = FileUtils.getEntry(file);
                     
                     result = new PluginResult(PluginResult.Status.OK, fileEntry);
                 } catch (FileNotFoundException e) {
@@ -826,7 +857,7 @@ public class FileTransfer extends CordovaPlugin {
                 file.delete();
             }
             // Trigger the abort callback immediately to minimize latency between it and abort() being called.
-            JSONObject error = createFileTransferError(ABORTED_ERR, context.source, context.target, -1);
+            JSONObject error = createFileTransferError(ABORTED_ERR, context.source, context.target, null, -1);
             synchronized (context) {
                 context.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, error));
                 context.aborted = true;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/FileUtils.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/FileUtils.java b/lib/cordova-android/framework/src/org/apache/cordova/FileUtils.java
index b461b02..2135be9 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/FileUtils.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/FileUtils.java
@@ -15,18 +15,17 @@
        KIND, either express or implied.  See the License for the
        specific language governing permissions and limitations
        under the License.
-*/
+ */
 package org.apache.cordova;
 
-import java.io.*;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLDecoder;
-import java.nio.channels.FileChannel;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.util.Log;
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaInterface;
 import org.apache.cordova.api.CordovaPlugin;
 import org.apache.cordova.api.PluginResult;
 import org.apache.cordova.file.EncodingException;
@@ -38,23 +37,25 @@ import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
-//import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Environment;
-import android.provider.MediaStore;
-import android.webkit.MimeTypeMap;
-
-//import android.app.Activity;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.nio.channels.FileChannel;
 
 /**
  * This class provides SD card file and directory services to JavaScript.
  * Only files on the SD card can be accessed.
  */
 public class FileUtils extends CordovaPlugin {
-    @SuppressWarnings("unused")
     private static final String LOG_TAG = "FileUtils";
-    private static final String _DATA = "_data";    // The column name where the file path is stored
 
     public static int NOT_FOUND_ERR = 1;
     public static int SECURITY_ERR = 2;
@@ -75,9 +76,6 @@ public class FileUtils extends CordovaPlugin {
     public static int RESOURCE = 2;
     public static int APPLICATION = 3;
 
-    FileReader f_in;
-    FileWriter f_out;
-
     /**
      * Constructor.
      */
@@ -111,30 +109,29 @@ public class FileUtils extends CordovaPlugin {
                 callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b));
             }
             else if (action.equals("readAsText")) {
-                int start = 0;
-                int end = Integer.MAX_VALUE;
-                if (args.length() >= 3) {
-                    start = args.getInt(2);
-                }
-                if (args.length() >= 4) {
-                    end = args.getInt(3);
-                }
+                String encoding = args.getString(1);
+                int start = args.getInt(2);
+                int end = args.getInt(3);
 
-                String s = this.readAsText(args.getString(0), args.getString(1), start, end);
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, s));
+                this.readFileAs(args.getString(0), start, end, callbackContext, encoding, PluginResult.MESSAGE_TYPE_STRING);
             }
             else if (action.equals("readAsDataURL")) {
-                int start = 0;
-                int end = Integer.MAX_VALUE;
-                if (args.length() >= 2) {
-                    start = args.getInt(1);
-                }
-                if (args.length() >= 3) {
-                    end = args.getInt(2);
-                }
+                int start = args.getInt(1);
+                int end = args.getInt(2);
+
+                this.readFileAs(args.getString(0), start, end, callbackContext, null, -1);
+            }
+            else if (action.equals("readAsArrayBuffer")) {
+                int start = args.getInt(1);
+                int end = args.getInt(2);
 
-                String s = this.readAsDataURL(args.getString(0), start, end);
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, s));
+                this.readFileAs(args.getString(0), start, end, callbackContext, null, PluginResult.MESSAGE_TYPE_ARRAYBUFFER);
+            }
+            else if (action.equals("readAsBinaryString")) {
+                int start = args.getInt(1);
+                int end = args.getInt(2);
+
+                this.readFileAs(args.getString(0), start, end, callbackContext, null, PluginResult.MESSAGE_TYPE_BINARYSTRING);
             }
             else if (action.equals("write")) {
                 long fileSize = this.write(args.getString(0), args.getString(1), args.getInt(2));
@@ -237,11 +234,11 @@ public class FileUtils extends CordovaPlugin {
      * @param filePath the path to check
      */
     private void notifyDelete(String filePath) {
-        String newFilePath = getRealPathFromURI(Uri.parse(filePath), cordova);
+        String newFilePath = FileHelper.getRealPath(filePath, cordova);
         try {
             this.cordova.getActivity().getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
-                MediaStore.Images.Media.DATA + " = ?",
-                new String[] { newFilePath });
+                    MediaStore.Images.Media.DATA + " = ?",
+                    new String[] { newFilePath });
         } catch (UnsupportedOperationException t) {
             // Was seeing this on the File mobile-spec tests on 4.0.3 x86 emulator.
             // The ContentResolver applies only when the file was registered in the
@@ -344,8 +341,8 @@ public class FileUtils extends CordovaPlugin {
      * @throws FileExistsException
      */
     private JSONObject transferTo(String fileName, String newParent, String newName, boolean move) throws JSONException, NoModificationAllowedException, IOException, InvalidModificationException, EncodingException, FileExistsException {
-        String newFileName = getRealPathFromURI(Uri.parse(fileName), cordova);
-        newParent = getRealPathFromURI(Uri.parse(newParent), cordova);
+        String newFileName = FileHelper.getRealPath(fileName, cordova);
+        newParent = FileHelper.getRealPath(newParent, cordova);
 
         // Check for invalid file name
         if (newName != null && newName.contains(":")) {
@@ -384,14 +381,14 @@ public class FileUtils extends CordovaPlugin {
             }
         } else {
             if (move) {
-            	JSONObject newFileEntry = moveFile(source, destination);
+                JSONObject newFileEntry = moveFile(source, destination);
 
-            	// If we've moved a file given its content URI, we need to clean up.
-            	if (fileName.startsWith("content://")) {
-            		notifyDelete(fileName);
-            	}
+                // If we've moved a file given its content URI, we need to clean up.
+                if (fileName.startsWith("content://")) {
+                    notifyDelete(fileName);
+                }
 
-            	return newFileEntry;
+                return newFileEntry;
             } else {
                 return copyFile(source, destination);
             }
@@ -748,7 +745,7 @@ public class FileUtils extends CordovaPlugin {
         if (fileName.startsWith("/")) {
             fp = new File(fileName);
         } else {
-            dirPath = getRealPathFromURI(Uri.parse(dirPath), cordova);
+            dirPath = FileHelper.getRealPath(dirPath, cordova);
             fp = new File(dirPath + File.separator + fileName);
         }
         return fp;
@@ -763,7 +760,7 @@ public class FileUtils extends CordovaPlugin {
      * @throws JSONException
      */
     private JSONObject getParent(String filePath) throws JSONException {
-        filePath = getRealPathFromURI(Uri.parse(filePath), cordova);
+        filePath = FileHelper.getRealPath(filePath, cordova);
 
         if (atRootDirectory(filePath)) {
             return getEntry(filePath);
@@ -779,7 +776,7 @@ public class FileUtils extends CordovaPlugin {
      * @return true if we are at the root, false otherwise.
      */
     private boolean atRootDirectory(String filePath) {
-        filePath = getRealPathFromURI(Uri.parse(filePath), cordova);
+        filePath = FileHelper.getRealPath(filePath, cordova);
 
         if (filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + cordova.getActivity().getPackageName() + "/cache") ||
                 filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath()) ||
@@ -790,26 +787,13 @@ public class FileUtils extends CordovaPlugin {
     }
 
     /**
-     * This method removes the "file://" from the passed in filePath
-     *
-     * @param filePath to be checked.
-     * @return
-     */
-    public static String stripFileProtocol(String filePath) {
-        if (filePath.startsWith("file://")) {
-            filePath = filePath.substring(7);
-        }
-        return filePath;
-    }
-
-    /**
      * Create a File object from the passed in path
      *
      * @param filePath
      * @return
      */
     private File createFileObject(String filePath) {
-    	filePath = getRealPathFromURI(Uri.parse(filePath), cordova);
+        filePath = FileHelper.getRealPath(filePath, cordova);
 
         File file = new File(filePath);
         return file;
@@ -849,7 +833,7 @@ public class FileUtils extends CordovaPlugin {
 
         JSONObject metadata = new JSONObject();
         metadata.put("size", file.length());
-        metadata.put("type", getMimeType(filePath));
+        metadata.put("type", FileHelper.getMimeType(filePath, cordova));
         metadata.put("name", file.getName());
         metadata.put("fullPath", filePath);
         metadata.put("lastModifiedDate", file.lastModified());
@@ -900,21 +884,21 @@ public class FileUtils extends CordovaPlugin {
     }
 
     /**
-     * Returns a JSON Object representing a directory on the device's file system
+     * Returns a JSON object representing the given File.
      *
-     * @param path to the directory
-     * @return
+     * @param file the File to convert
+     * @return a JSON representation of the given File
      * @throws JSONException
      */
-    public JSONObject getEntry(File file) throws JSONException {
+    public static JSONObject getEntry(File file) throws JSONException {
         JSONObject entry = new JSONObject();
 
         entry.put("isFile", file.isFile());
         entry.put("isDirectory", file.isDirectory());
         entry.put("name", file.getName());
         entry.put("fullPath", "file://" + file.getAbsolutePath());
-        // I can't add the next thing it as it would be an infinite loop
-        //entry.put("filesystem", null);
+        // The file system can't be specified, as it would lead to an infinite loop.
+        // entry.put("filesystem", null);
 
         return entry;
     }
@@ -930,123 +914,83 @@ public class FileUtils extends CordovaPlugin {
         return getEntry(new File(path));
     }
 
-    /**
-     * Identifies if action to be executed returns a value and should be run synchronously.
-     *
-     * @param action	The action to execute
-     * @return			T=returns value
-     */
-    public boolean isSynch(String action) {
-        if (action.equals("testSaveLocationExists")) {
-            return true;
-        }
-        else if (action.equals("getFreeDiskSpace")) {
-            return true;
-        }
-        else if (action.equals("testFileExists")) {
-            return true;
-        }
-        else if (action.equals("testDirectoryExists")) {
-            return true;
-        }
-        return false;
-    }
 
     //--------------------------------------------------------------------------
     // LOCAL METHODS
     //--------------------------------------------------------------------------
 
     /**
-     * Read content of text file.
+     * Read the contents of a file.
+     * This is done in a background thread; the result is sent to the callback.
      *
-     * @param filename			The name of the file.
-     * @param encoding			The encoding to return contents as.  Typical value is UTF-8.
-     * 							(see http://www.iana.org/assignments/character-sets)
-     * @param start                     Start position in the file.
-     * @param end                       End position to stop at (exclusive).
-     * @return					Contents of file.
-     * @throws FileNotFoundException, IOException
+     * @param filename          The name of the file.
+     * @param start             Start position in the file.
+     * @param end               End position to stop at (exclusive).
+     * @param callbackContext   The context through which to send the result.
+     * @param encoding          The encoding to return contents as.  Typical value is UTF-8. (see http://www.iana.org/assignments/character-sets)
+     * @param resultType        The desired type of data to send to the callback.
+     * @return                  Contents of file.
      */
-    public String readAsText(String filename, String encoding, int start, int end) throws FileNotFoundException, IOException {
-        int diff = end - start;
-        byte[] bytes = new byte[1000];
-        BufferedInputStream bis = new BufferedInputStream(getPathFromUri(filename), 1024);
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        int numRead = 0;
-
-        if (start > 0) {
-            bis.skip(start);
-        }
-
-        while ( diff > 0 && (numRead = bis.read(bytes, 0, Math.min(1000, diff))) >= 0) {
-            diff -= numRead;
-            bos.write(bytes, 0, numRead);
-        }
-
-        return new String(bos.toByteArray(), encoding);
+    public void readFileAs(final String filename, final int start, final int end, final CallbackContext callbackContext, final String encoding, final int resultType) {
+        this.cordova.getThreadPool().execute(new Runnable() {
+            public void run() {
+                try {
+                    byte[] bytes = readAsBinaryHelper(filename, start, end);
+                    
+                    PluginResult result;
+                    switch (resultType) {
+                        case PluginResult.MESSAGE_TYPE_STRING:
+                            result = new PluginResult(PluginResult.Status.OK, new String(bytes, encoding));
+                            break;
+                        case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
+                            result = new PluginResult(PluginResult.Status.OK, bytes);
+                            break;
+                        case PluginResult.MESSAGE_TYPE_BINARYSTRING:
+                            result = new PluginResult(PluginResult.Status.OK, bytes, true);
+                            break;
+                        default: // Base64.
+                            String contentType = FileHelper.getMimeType(filename, cordova);
+                            byte[] base64 = Base64.encodeBase64(bytes);
+                            String s = "data:" + contentType + ";base64," + new String(base64, "US-ASCII");
+                            result = new PluginResult(PluginResult.Status.OK, s);
+                    }
+
+                    callbackContext.sendPluginResult(result);
+                } catch (FileNotFoundException e) {
+                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, NOT_FOUND_ERR));
+                } catch (IOException e) {
+                    Log.d(LOG_TAG, e.getLocalizedMessage());
+                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, NOT_READABLE_ERR));
+                }
+            }
+        });
     }
 
     /**
-     * Read content of text file and return as base64 encoded data url.
+     * Read the contents of a file as binary.
+     * This is done synchronously; the result is returned.
      *
-     * @param filename			The name of the file.
-     * @return					Contents of file = data:<media type>;base64,<data>
-     * @throws FileNotFoundException, IOException
+     * @param filename          The name of the file.
+     * @param start             Start position in the file.
+     * @param end               End position to stop at (exclusive).
+     * @return                  Contents of the file as a byte[].
+     * @throws IOException
      */
-    public String readAsDataURL(String filename, int start, int end) throws FileNotFoundException, IOException {
-        int diff = end - start;
-        byte[] bytes = new byte[1000];
-        BufferedInputStream bis = new BufferedInputStream(getPathFromUri(filename), 1024);
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        int numRead = 0;
+    private byte[] readAsBinaryHelper(String filename, int start, int end) throws IOException {
+        int numBytesToRead = end - start;
+        byte[] bytes = new byte[numBytesToRead];
+        InputStream inputStream = FileHelper.getInputStreamFromUriString(filename, cordova);
+        int numBytesRead = 0;
 
         if (start > 0) {
-            bis.skip(start);
-        }
-
-        while (diff > 0 && (numRead = bis.read(bytes, 0, Math.min(1000, diff))) >= 0) {
-            diff -= numRead;
-            bos.write(bytes, 0, numRead);
+            inputStream.skip(start);
         }
 
-        // Determine content type from file name
-        String contentType = null;
-        if (filename.startsWith("content:")) {
-            Uri fileUri = Uri.parse(filename);
-            contentType = this.cordova.getActivity().getContentResolver().getType(fileUri);
-        }
-        else {
-            contentType = getMimeType(filename);
+        while (numBytesToRead > 0 && (numBytesRead = inputStream.read(bytes, numBytesRead, numBytesToRead)) >= 0) {
+            numBytesToRead -= numBytesRead;
         }
 
-        byte[] base64 = Base64.encodeBase64(bos.toByteArray());
-        String data = "data:" + contentType + ";base64," + new String(base64);
-        return data;
-    }
-
-    /**
-     * Looks up the mime type of a given file name.
-     *
-     * @param filename
-     * @return a mime type
-     */
-    public static String getMimeType(String filename) {
-        if (filename != null) {
-            // Stupid bug in getFileExtensionFromUrl when the file name has a space
-            // So we need to replace the space with a url encoded %20
-
-            // CB-2185: Stupid bug not putting JPG extension in the mime-type map
-            String url = filename.replace(" ", "%20").toLowerCase();
-            MimeTypeMap map = MimeTypeMap.getSingleton();
-            String extension = MimeTypeMap.getFileExtensionFromUrl(url);
-            if (extension.toLowerCase().equals("3ga")) {
-                return "audio/3gpp";
-            } else {
-                return map.getMimeTypeFromExtension(extension);
-            }
-        } else {
-            return "";
-        }
+        return bytes;
     }
 
     /**
@@ -1060,11 +1004,11 @@ public class FileUtils extends CordovaPlugin {
      */
     /**/
     public long write(String filename, String data, int offset) throws FileNotFoundException, IOException, NoModificationAllowedException {
-    	if (filename.startsWith("content://")) {
-    		throw new NoModificationAllowedException("Couldn't write to file given its content URI");
-    	}
+        if (filename.startsWith("content://")) {
+            throw new NoModificationAllowedException("Couldn't write to file given its content URI");
+        }
 
-        filename = getRealPathFromURI(Uri.parse(filename), cordova);
+        filename = FileHelper.getRealPath(filename, cordova);
 
         boolean append = false;
         if (offset > 0) {
@@ -1093,11 +1037,11 @@ public class FileUtils extends CordovaPlugin {
      * @throws NoModificationAllowedException
      */
     private long truncateFile(String filename, long size) throws FileNotFoundException, IOException, NoModificationAllowedException {
-    	if (filename.startsWith("content://")) {
-    		throw new NoModificationAllowedException("Couldn't truncate file given its content URI");
-    	}
+        if (filename.startsWith("content://")) {
+            throw new NoModificationAllowedException("Couldn't truncate file given its content URI");
+        }
 
-        filename = getRealPathFromURI(Uri.parse(filename), cordova);
+        filename = FileHelper.getRealPath(filename, cordova);
 
         RandomAccessFile raf = new RandomAccessFile(filename, "rw");
         try {
@@ -1112,48 +1056,4 @@ public class FileUtils extends CordovaPlugin {
             raf.close();
         }
     }
-
-    /**
-     * Get an input stream based on file path or content:// uri
-     *
-     * @param path
-     * @return an input stream
-     * @throws FileNotFoundException
-     */
-    private InputStream getPathFromUri(String path) throws FileNotFoundException {
-        if (path.startsWith("content")) {
-            Uri uri = Uri.parse(path);
-            return cordova.getActivity().getContentResolver().openInputStream(uri);
-        }
-        else {
-            path = getRealPathFromURI(Uri.parse(path), cordova);
-            return new FileInputStream(path);
-        }
-    }
-
-    /**
-     * Queries the media store to find out what the file path is for the Uri we supply
-     *
-     * @param contentUri the Uri of the audio/image/video
-     * @param cordova the current application context
-     * @return the full path to the file
-     */
-    @SuppressWarnings("deprecation")
-    protected static String getRealPathFromURI(Uri contentUri, CordovaInterface cordova) {
-        final String scheme = contentUri.getScheme();
-
-        if (scheme == null) {
-        	return contentUri.toString();
-    	} else if (scheme.compareTo("content") == 0) {
-            String[] proj = { _DATA };
-            Cursor cursor = cordova.getActivity().managedQuery(contentUri, proj, null, null, null);
-            int column_index = cursor.getColumnIndexOrThrow(_DATA);
-            cursor.moveToFirst();
-            return cursor.getString(column_index);
-        } else if (scheme.compareTo("file") == 0) {
-            return contentUri.getPath();
-        } else {
-            return contentUri.toString();
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/GeoBroker.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/GeoBroker.java b/lib/cordova-android/framework/src/org/apache/cordova/GeoBroker.java
index 86aa628..e7cdce0 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/GeoBroker.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/GeoBroker.java
@@ -150,7 +150,7 @@ public class GeoBroker extends CordovaPlugin {
             o.put("altitude", (loc.hasAltitude() ? loc.getAltitude() : null));
             o.put("accuracy", loc.getAccuracy());
             o.put("heading", (loc.hasBearing() ? (loc.hasSpeed() ? loc.getBearing() : null) : null));
-            o.put("speed", loc.getSpeed());
+            o.put("velocity", loc.getSpeed());
             o.put("timestamp", loc.getTime());
         } catch (JSONException e) {
             // TODO Auto-generated catch block

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java b/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
index a96b242..2142714 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
@@ -42,7 +42,7 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
 
     @Override
     public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
-        if(url.contains("?") || url.contains("#")){
+        if(url.contains("?") || url.contains("#") || needsIceCreamSpaceInAssetUrlFix(url)){
             return generateWebResourceResponse(url);
         } else {
             return super.shouldInterceptRequest(view, url);
@@ -80,4 +80,18 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
         return null;
     }
     
+    private static boolean needsIceCreamSpaceInAssetUrlFix(String url) {
+        if (!url.contains("%20")){
+            return false;
+        }
+
+        switch(android.os.Build.VERSION.SDK_INT){
+            case android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH:
+            case android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1:
+                return true;
+            default:
+                return false;
+        }
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java b/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
index 7e7f862..48e27c6 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
@@ -35,7 +35,9 @@ import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.graphics.Bitmap;
+import android.graphics.Color;
 import android.net.Uri;
+import android.os.Bundle;
 import android.text.InputType;
 import android.util.Log;
 import android.util.TypedValue;
@@ -48,6 +50,7 @@ import android.view.WindowManager.LayoutParams;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.webkit.WebChromeClient;
+import android.webkit.GeolocationPermissions.Callback;
 import android.webkit.WebSettings;
 import android.webkit.WebStorage;
 import android.webkit.WebView;
@@ -69,6 +72,8 @@ public class InAppBrowser extends CordovaPlugin {
     private static final String EXIT_EVENT = "exit";
     private static final String LOAD_START_EVENT = "loadstart";
     private static final String LOAD_STOP_EVENT = "loadstop";
+    private static final String LOAD_ERROR_EVENT = "loaderror";
+    private static final String CLOSE_BUTTON_CAPTION = "closebuttoncaption";
     private long MAX_QUOTA = 100 * 1024 * 1024;
 
     private Dialog dialog;
@@ -76,6 +81,7 @@ public class InAppBrowser extends CordovaPlugin {
     private EditText edittext;
     private boolean showLocationBar = true;
     private CallbackContext callbackContext;
+    private String buttonLabel = "Done";
     
     /**
      * Executes the request and returns PluginResult.
@@ -174,8 +180,12 @@ public class InAppBrowser extends CordovaPlugin {
                 option = new StringTokenizer(features.nextToken(), "=");
                 if (option.hasMoreElements()) {
                     String key = option.nextToken();
-                    Boolean value = option.nextToken().equals("no") ? Boolean.FALSE : Boolean.TRUE;
-                    map.put(key, value);
+                    if (key.equalsIgnoreCase(CLOSE_BUTTON_CAPTION)) {
+                        this.buttonLabel = option.nextToken();
+                    } else {
+                        Boolean value = option.nextToken().equals("no") ? Boolean.FALSE : Boolean.TRUE;
+                        map.put(key, value);
+                    }
                 }
             }
             return map;
@@ -221,6 +231,7 @@ public class InAppBrowser extends CordovaPlugin {
      */
     private void closeDialog() {
         try {
+            this.inAppWebView.loadUrl("about:blank");
             JSONObject obj = new JSONObject();
             obj.put("type", EXIT_EVENT);
 
@@ -289,7 +300,10 @@ public class InAppBrowser extends CordovaPlugin {
         // Determine if we should hide the location bar.
         showLocationBar = true;
         if (features != null) {
-            showLocationBar = features.get(LOCATION).booleanValue();
+            Boolean show = features.get(LOCATION);
+            if (show != null) {
+                showLocationBar = show.booleanValue();
+            }
         }
         
         final CordovaWebView thatWebView = this.webView;
@@ -405,7 +419,7 @@ public class InAppBrowser extends CordovaPlugin {
                 close.setLayoutParams(closeLayoutParams);
                 forward.setContentDescription("Close Button");
                 close.setId(5);
-                close.setText("Done");
+                close.setText(buttonLabel);
                 close.setOnClickListener(new View.OnClickListener() {
                     public void onClick(View v) {
                         closeDialog();
@@ -428,10 +442,18 @@ public class InAppBrowser extends CordovaPlugin {
                  */
                 // @TODO: replace with settings.setPluginState(android.webkit.WebSettings.PluginState.ON)
                 settings.setPluginsEnabled(true);
-                settings.setDatabaseEnabled(true);
-                String databasePath = cordova.getActivity().getApplicationContext().getDir("inAppBrowserDB", Context.MODE_PRIVATE).getPath();
-                settings.setDatabasePath(databasePath);
+                
+                //Toggle whether this is enabled or not!
+                Bundle appSettings = cordova.getActivity().getIntent().getExtras();
+                boolean enableDatabase = appSettings.getBoolean("InAppBrowserStorageEnabled", true);
+                if(enableDatabase)
+                {
+                    String databasePath = cordova.getActivity().getApplicationContext().getDir("inAppBrowserDB", Context.MODE_PRIVATE).getPath();
+                    settings.setDatabasePath(databasePath);
+                    settings.setDatabaseEnabled(true);
+                }
                 settings.setDomStorageEnabled(true);
+               
                 inAppWebView.loadUrl(url);
                 inAppWebView.setId(6);
                 inAppWebView.getSettings().setLoadWithOverviewMode(true);
@@ -472,16 +494,24 @@ public class InAppBrowser extends CordovaPlugin {
     }
 
     /**
-     * Create a new plugin result and send it back to JavaScript
+     * Create a new plugin success result and send it back to JavaScript
      *
      * @param obj a JSONObject contain event payload information
      */
     private void sendUpdate(JSONObject obj, boolean keepCallback) {
-        PluginResult result = new PluginResult(PluginResult.Status.OK, obj);
+        sendUpdate(obj, keepCallback, PluginResult.Status.OK);
+    }
+
+    /**
+     * Create a new plugin result and send it back to JavaScript
+     *
+     * @param obj a JSONObject contain event payload information
+     * @param status the status code to return to the JavaScript environment
+     */    private void sendUpdate(JSONObject obj, boolean keepCallback, PluginResult.Status status) {
+        PluginResult result = new PluginResult(status, obj);
         result.setKeepCallback(keepCallback);
         this.callbackContext.sendPluginResult(result);
     }
-
     public class InAppChromeClient extends WebChromeClient {
 
         /**
@@ -514,6 +544,18 @@ public class InAppBrowser extends CordovaPlugin {
                 quotaUpdater.updateQuota(currentQuota);
             }
         }
+
+        /**
+         * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin.
+         *
+         * @param origin
+         * @param callback
+         */
+        @Override
+        public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
+            super.onGeolocationPermissionsShowPrompt(origin, callback);
+            callback.invoke(origin, true, false);
+        }
     }
     
     /**
@@ -543,10 +585,62 @@ public class InAppBrowser extends CordovaPlugin {
         @Override
         public void onPageStarted(WebView view, String url,  Bitmap favicon) {
             super.onPageStarted(view, url, favicon);
-            String newloc;
+            String newloc = "";
             if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:")) {
                 newloc = url;
-            } else {
+            } 
+            // If dialing phone (tel:5551212)
+            else if (url.startsWith(WebView.SCHEME_TEL)) {
+                try {
+                    Intent intent = new Intent(Intent.ACTION_DIAL);
+                    intent.setData(Uri.parse(url));
+                    cordova.getActivity().startActivity(intent);
+                } catch (android.content.ActivityNotFoundException e) {
+                    LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
+                }
+            }
+
+            else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:")) {
+                try {
+                    Intent intent = new Intent(Intent.ACTION_VIEW);
+                    intent.setData(Uri.parse(url));
+                    cordova.getActivity().startActivity(intent);
+                } catch (android.content.ActivityNotFoundException e) {
+                    LOG.e(LOG_TAG, "Error with " + url + ": " + e.toString());
+                }
+            }
+            // If sms:5551212?body=This is the message
+            else if (url.startsWith("sms:")) {
+                try {
+                    Intent intent = new Intent(Intent.ACTION_VIEW);
+
+                    // Get address
+                    String address = null;
+                    int parmIndex = url.indexOf('?');
+                    if (parmIndex == -1) {
+                        address = url.substring(4);
+                    }
+                    else {
+                        address = url.substring(4, parmIndex);
+
+                        // If body, then set sms body
+                        Uri uri = Uri.parse(url);
+                        String query = uri.getQuery();
+                        if (query != null) {
+                            if (query.startsWith("body=")) {
+                                intent.putExtra("sms_body", query.substring(5));
+                            }
+                        }
+                    }
+                    intent.setData(Uri.parse("sms:" + address));
+                    intent.putExtra("address", address);
+                    intent.setType("vnd.android-dir/mms-sms");
+                    cordova.getActivity().startActivity(intent);
+                } catch (android.content.ActivityNotFoundException e) {
+                    LOG.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
+                }
+            }
+            else {
                 newloc = "http://" + url;
             }
 
@@ -578,5 +672,22 @@ public class InAppBrowser extends CordovaPlugin {
                 Log.d(LOG_TAG, "Should never happen");
             }
         }
+        
+        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
+            super.onReceivedError(view, errorCode, description, failingUrl);
+            
+            try {
+                JSONObject obj = new JSONObject();
+                obj.put("type", LOAD_ERROR_EVENT);
+                obj.put("url", failingUrl);
+                obj.put("code", errorCode);
+                obj.put("message", description);
+    
+                sendUpdate(obj, true, PluginResult.Status.ERROR);
+            } catch (JSONException ex) {
+                Log.d(LOG_TAG, "Should never happen");
+            }
+        	
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/JSONUtils.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/JSONUtils.java b/lib/cordova-android/framework/src/org/apache/cordova/JSONUtils.java
new file mode 100644
index 0000000..77df876
--- /dev/null
+++ b/lib/cordova-android/framework/src/org/apache/cordova/JSONUtils.java
@@ -0,0 +1,24 @@
+package org.apache.cordova;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+
+public class JSONUtils {
+	public static List<String> toStringList(JSONArray array) throws JSONException {
+        if(array == null) {
+            return null;
+        }
+        else {
+            List<String> list = new ArrayList<String>();
+
+            for (int i = 0; i < array.length(); i++) {
+                list.add(array.get(i).toString());
+            }
+
+            return list;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java b/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
index 83e1778..ea684a4 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
@@ -409,6 +409,9 @@ public class NativeToJsMessageQueue {
                 case PluginResult.MESSAGE_TYPE_STRING: // s
                     ret += 1 + pluginResult.getStrMessage().length();
                     break;
+                case PluginResult.MESSAGE_TYPE_BINARYSTRING:
+                    ret += 1 + pluginResult.getMessage().length();
+                    break;
                 case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
                     ret += 1 + pluginResult.getMessage().length();
                     break;
@@ -451,7 +454,11 @@ public class NativeToJsMessageQueue {
                     sb.append('s');
                     sb.append(pluginResult.getStrMessage());
                     break;
-                case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
+                case PluginResult.MESSAGE_TYPE_BINARYSTRING: // S
+                    sb.append('S');
+                    sb.append(pluginResult.getMessage());
+                    break;                    
+                case PluginResult.MESSAGE_TYPE_ARRAYBUFFER: // A
                     sb.append('A');
                     sb.append(pluginResult.getMessage());
                     break;
@@ -473,9 +480,9 @@ public class NativeToJsMessageQueue {
                   .append(success)
                   .append(",")
                   .append(status)
-                  .append(",")
+                  .append(",[")
                   .append(pluginResult.getMessage())
-                  .append(",")
+                  .append("],")
                   .append(pluginResult.getKeepCallback())
                   .append(");");
             }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/Notification.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/Notification.java b/lib/cordova-android/framework/src/org/apache/cordova/Notification.java
index 958ab26..9d96062 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/Notification.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/Notification.java
@@ -24,6 +24,7 @@ import org.apache.cordova.api.CordovaPlugin;
 import org.apache.cordova.api.PluginResult;
 import org.json.JSONArray;
 import org.json.JSONException;
+import org.json.JSONObject;
 import android.app.AlertDialog;
 import android.app.ProgressDialog;
 import android.content.Context;
@@ -32,6 +33,7 @@ import android.media.Ringtone;
 import android.media.RingtoneManager;
 import android.net.Uri;
 import android.os.Vibrator;
+import android.widget.EditText;
 
 /**
  * This class provides access to notifications on the device.
@@ -68,7 +70,11 @@ public class Notification extends CordovaPlugin {
             return true;
         }
         else if (action.equals("confirm")) {
-            this.confirm(args.getString(0), args.getString(1), args.getString(2), callbackContext);
+            this.confirm(args.getString(0), args.getString(1), args.getJSONArray(2), callbackContext);
+            return true;
+        }
+        else if (action.equals("prompt")) {
+            this.prompt(args.getString(0), args.getString(1), args.getJSONArray(2), callbackContext);
             return true;
         }
         else if (action.equals("activityStart")) {
@@ -170,7 +176,7 @@ public class Notification extends CordovaPlugin {
                         callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0));
                     }
                 });
-                
+
                 dlg.create();
                 dlg.show();
             };
@@ -188,10 +194,9 @@ public class Notification extends CordovaPlugin {
      * @param buttonLabels      A comma separated list of button labels (Up to 3 buttons)
      * @param callbackContext   The callback context.
      */
-    public synchronized void confirm(final String message, final String title, String buttonLabels, final CallbackContext callbackContext) {
+    public synchronized void confirm(final String message, final String title, final JSONArray buttonLabels, final CallbackContext callbackContext) {
 
         final CordovaInterface cordova = this.cordova;
-        final String[] fButtons = buttonLabels.split(",");
 
         Runnable runnable = new Runnable() {
             public void run() {
@@ -201,37 +206,43 @@ public class Notification extends CordovaPlugin {
                 dlg.setCancelable(true);
 
                 // First button
-                if (fButtons.length > 0) {
-                    dlg.setNegativeButton(fButtons[0],
-                            new AlertDialog.OnClickListener() {
-                                public void onClick(DialogInterface dialog, int which) {
-                                    dialog.dismiss();
-                                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 1));
-                                }
-                            });
+                if (buttonLabels.length() > 0) {
+                    try {
+						dlg.setNegativeButton(buttonLabels.getString(0),
+						        new AlertDialog.OnClickListener() {
+						            public void onClick(DialogInterface dialog, int which) {
+						                dialog.dismiss();
+						                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 1));
+						            }
+						        });
+					} catch (JSONException e) { }
                 }
 
                 // Second button
-                if (fButtons.length > 1) {
-                    dlg.setNeutralButton(fButtons[1],
-                            new AlertDialog.OnClickListener() {
-                                public void onClick(DialogInterface dialog, int which) {
-                                    dialog.dismiss();
-                                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 2));
-                                }
-                            });
+                if (buttonLabels.length() > 1) {
+                    try {
+						dlg.setNeutralButton(buttonLabels.getString(1),
+						        new AlertDialog.OnClickListener() {
+						            public void onClick(DialogInterface dialog, int which) {
+						                dialog.dismiss();
+						                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 2));
+						            }
+						        });
+					} catch (JSONException e) { }
                 }
 
                 // Third button
-                if (fButtons.length > 2) {
-                    dlg.setPositiveButton(fButtons[2],
-                            new AlertDialog.OnClickListener() {
-                                public void onClick(DialogInterface dialog, int which) {
-                                    dialog.dismiss();
-                                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 3));
-                                }
-                            }
-                            );
+                if (buttonLabels.length() > 2) {
+                    try {
+						dlg.setPositiveButton(buttonLabels.getString(2),
+						        new AlertDialog.OnClickListener() {
+						            public void onClick(DialogInterface dialog, int which) {
+						                dialog.dismiss();
+						                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 3));
+						            }
+						        }
+						        );
+					} catch (JSONException e) { }
                 }
                 dlg.setOnCancelListener(new AlertDialog.OnCancelListener() {
                     public void onCancel(DialogInterface dialog)
@@ -249,6 +260,104 @@ public class Notification extends CordovaPlugin {
     }
 
     /**
+     * Builds and shows a native Android prompt dialog with given title, message, buttons.
+     * This dialog only shows up to 3 buttons.  Any labels after that will be ignored.
+     * The following results are returned to the JavaScript callback identified by callbackId:
+     *     buttonIndex			Index number of the button selected
+     *     input1				The text entered in the prompt dialog box
+     *
+     * @param message           The message the dialog should display
+     * @param title             The title of the dialog
+     * @param buttonLabels      A comma separated list of button labels (Up to 3 buttons)
+     * @param callbackContext   The callback context.
+     */
+    public synchronized void prompt(final String message, final String title, final JSONArray buttonLabels, final CallbackContext callbackContext) {
+    	
+        final CordovaInterface cordova = this.cordova;
+        final EditText promptInput =  new EditText(cordova.getActivity());
+
+        Runnable runnable = new Runnable() {
+            public void run() {
+                AlertDialog.Builder dlg = new AlertDialog.Builder(cordova.getActivity());
+                dlg.setMessage(message);
+                dlg.setTitle(title);
+                dlg.setCancelable(true);
+                
+                dlg.setView(promptInput);
+                
+                final JSONObject result = new JSONObject();
+                
+                // First button
+                if (buttonLabels.length() > 0) {
+                    try {
+						dlg.setNegativeButton(buttonLabels.getString(0),
+						        new AlertDialog.OnClickListener() {
+						            public void onClick(DialogInterface dialog, int which) {
+						                dialog.dismiss();
+						                try {
+											result.put("buttonIndex",1);
+							                result.put("input1", promptInput.getText());
+										} catch (JSONException e) { e.printStackTrace(); }
+						                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result));
+						            }
+						        });
+					} catch (JSONException e) { }
+                }
+
+                // Second button
+                if (buttonLabels.length() > 1) {
+                    try {
+						dlg.setNeutralButton(buttonLabels.getString(1),
+						        new AlertDialog.OnClickListener() {
+						            public void onClick(DialogInterface dialog, int which) {
+						                dialog.dismiss();
+						                try {
+											result.put("buttonIndex",2);
+							                result.put("input1", promptInput.getText());
+										} catch (JSONException e) { e.printStackTrace(); }
+						                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result));
+						            }
+						        });
+					} catch (JSONException e) { }
+                }
+
+                // Third button
+                if (buttonLabels.length() > 2) {
+                    try {
+						dlg.setPositiveButton(buttonLabels.getString(2),
+						        new AlertDialog.OnClickListener() {
+						            public void onClick(DialogInterface dialog, int which) {
+						                dialog.dismiss();
+						                try {
+											result.put("buttonIndex",3);
+							                result.put("input1", promptInput.getText());
+										} catch (JSONException e) { e.printStackTrace(); }
+						                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result));
+						            }
+						        }
+						        );
+					} catch (JSONException e) { }
+                }
+                dlg.setOnCancelListener(new AlertDialog.OnCancelListener() {
+                    public void onCancel(DialogInterface dialog)
+                    {
+                        dialog.dismiss();
+		                try {
+							result.put("buttonIndex",0);
+			                result.put("input1", promptInput.getText());
+						} catch (JSONException e) { e.printStackTrace(); }
+		                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result));
+                    }
+                });
+
+                dlg.create();
+                dlg.show();
+                
+            };
+        };
+        this.cordova.getActivity().runOnUiThread(runnable);
+    }
+    /**
      * Show the spinner.
      *
      * @param title     Title of the dialog

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/api/CallbackContext.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/CallbackContext.java b/lib/cordova-android/framework/src/org/apache/cordova/api/CallbackContext.java
index 2f7b15f..a5d1255 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/api/CallbackContext.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/CallbackContext.java
@@ -79,6 +79,15 @@ public class CallbackContext {
     public void success(byte[] message) {
         sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
     }
+    
+    /**
+     * Helper for success callbacks that just returns the Status.OK by default
+     *
+     * @param message           The message to add to the success result.
+     */
+    public void success(int message) {
+        sendPluginResult(new PluginResult(PluginResult.Status.OK, message));
+    }
 
     /**
      * Helper for success callbacks that just returns the Status.OK by default

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaPlugin.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaPlugin.java b/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaPlugin.java
index f4c785e..2b225e6 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaPlugin.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaPlugin.java
@@ -22,7 +22,12 @@ import org.apache.cordova.CordovaArgs;
 import org.apache.cordova.CordovaWebView;
 import org.json.JSONArray;
 import org.json.JSONException;
+
+import android.annotation.TargetApi;
 import android.content.Intent;
+import android.os.Build;
+import android.util.Log;
+import android.webkit.WebResourceResponse;
 
 /**
  * Plugins must extend this class and override one of the execute methods.
@@ -150,7 +155,7 @@ public class CordovaPlugin {
     }
 
     /**
-     * By specifying a <url-filter> in plugins.xml you can map a URL (using startsWith atm) to this method.
+     * By specifying a <url-filter> in config.xml you can map a URL (using startsWith atm) to this method.
      *
      * @param url				The URL that is trying to be loaded in the Cordova webview.
      * @return					Return true to prevent the URL from loading. Default is false.
@@ -160,6 +165,17 @@ public class CordovaPlugin {
     }
 
     /**
+     * By specifying a <url-filter> in config.xml you can map a URL prefix to this method. It applies to all resources loaded in the WebView, not just top-level navigation.
+     *
+     * @param url               The URL of the resource to be loaded.
+     * @return                  Return a WebResourceResponse for the resource, or null to let the WebView handle it normally.
+     */
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+	public WebResourceResponse shouldInterceptRequest(String url) {
+        return null;
+    }
+
+    /**
      * Called when the WebView does a top-level navigation or refreshes.
      *
      * Plugins should stop any long-running processes and clean up internal state.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java b/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
index d0e6aef..337ef12 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
@@ -30,6 +30,8 @@ import org.xmlpull.v1.XmlPullParserException;
 import android.content.Intent;
 import android.content.res.XmlResourceParser;
 
+import android.webkit.WebResourceResponse;
+
 /**
  * PluginManager is exposed to JavaScript in the Cordova WebView.
  *
@@ -118,7 +120,7 @@ public class PluginManager {
                     // System.out.println("Plugin: "+name+" => "+value);
                     onload = "true".equals(xml.getAttributeValue(null, "onload"));
                     entry = new PluginEntry(service, pluginClass, onload);
-                    this.addService(entry);                   
+                    this.addService(entry);
                 }
                 //What is this?
                 else if (strNode.equals("url-filter")) {
@@ -367,6 +369,25 @@ public class PluginManager {
     }
 
     /**
+     * Called when the WebView is loading any resource, top-level or not.
+     *
+     * Uses the same url-filter tag as onOverrideUrlLoading.
+     *
+     * @param url               The URL of the resource to be loaded.
+     * @return                  Return a WebResourceResponse with the resource, or null if the WebView should handle it.
+     */
+    public WebResourceResponse shouldInterceptRequest(String url) {
+        Iterator<Entry<String, String>> it = this.urlMap.entrySet().iterator();
+        while (it.hasNext()) {
+            HashMap.Entry<String, String> pairs = it.next();
+            if (url.startsWith(pairs.getKey())) {
+                return this.getPlugin(pairs.getValue()).shouldInterceptRequest(url);
+            }
+        }
+        return null;
+    }
+
+    /**
      * Called when the app navigates or refreshes.
      */
     public void onReset() {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/api/PluginResult.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/PluginResult.java b/lib/cordova-android/framework/src/org/apache/cordova/api/PluginResult.java
index 4c1d833..a642200 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/api/PluginResult.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/PluginResult.java
@@ -71,11 +71,15 @@ public class PluginResult {
     }
 
     public PluginResult(Status status, byte[] data) {
+        this(status, data, false);
+    }
+
+    public PluginResult(Status status, byte[] data, boolean binaryString) {
         this.status = status.ordinal();
-        this.messageType = MESSAGE_TYPE_ARRAYBUFFER;
+        this.messageType = binaryString ? MESSAGE_TYPE_BINARYSTRING : MESSAGE_TYPE_ARRAYBUFFER;
         this.encodedMessage = Base64.encodeToString(data, Base64.NO_WRAP);
     }
-
+    
     public void setKeepCallback(boolean b) {
         this.keepCallback = b;
     }
@@ -143,6 +147,9 @@ public class PluginResult {
     public static final int MESSAGE_TYPE_BOOLEAN = 4;
     public static final int MESSAGE_TYPE_NULL = 5;
     public static final int MESSAGE_TYPE_ARRAYBUFFER = 6;
+    // Use BINARYSTRING when your string may contain null characters.
+    // This is required to work around a bug in the platform :(.
+    public static final int MESSAGE_TYPE_BINARYSTRING = 7;
 
     public static String[] StatusMessages = new String[] {
         "No result",

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-blackberry/bin/create
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/create b/lib/cordova-blackberry/bin/create
index 870bad1..b7e719b 100755
--- a/lib/cordova-blackberry/bin/create
+++ b/lib/cordova-blackberry/bin/create
@@ -56,6 +56,19 @@ function on_error {
     [ -d "$PROJECT_PATH" ] && rm -rf "$PROJECT_PATH"
 }
 
+function replace {
+    local pattern=$1
+    local filename=$2
+    # Mac OS X requires -i argument
+    if [[ "$OSTYPE" =~ "darwin" ]]
+    then
+        /usr/bin/sed -i '' -e $pattern "$filename"
+    elif [[ "$OSTYPE" =~ "linux" ]]
+    then
+        /bin/sed -i -e $pattern "$filename"
+    fi
+}
+
 # we do not want the script to silently fail
 trap on_error ERR
 trap on_exit EXIT
@@ -79,13 +92,13 @@ then
 	(cd "$BUILD_PATH" && "$ANT" create -Dproject.path="$PROJECT_PATH" &> /dev/null )
     # interpolate the activity and package into config.xml
     echo "Updating config.xml ..."
-    sed -i '' -e "s/__NAME__/${NAME}/g" "$MANIFEST_PATH"
-    sed -i '' -e "s/__PACKAGE__/${PACKAGE}/g" "$MANIFEST_PATH"
+    replace "s/__NAME__/${NAME}/g" "$MANIFEST_PATH"
+    replace "s/__PACKAGE__/${PACKAGE}/g" "$MANIFEST_PATH"
 else
 	# copy project template if in distribution
 	echo "Copying assets and resources ..."
 	cp -r "$BUILD_PATH/sample/." "$PROJECT_PATH"
     echo "Updating config.xml ..."
-    sed -i '' -e "s/cordovaExample/${NAME}/g" "$MANIFEST_PATH"
-    sed -i '' -e "s/org.apache.cordova.example/${PACKAGE}/g" "$MANIFEST_PATH"
+    replace "s/cordovaExample/${NAME}/g" "$MANIFEST_PATH"
+    replace "s/org.apache.cordova.example/${PACKAGE}/g" "$MANIFEST_PATH"
 fi

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-blackberry/bin/templates/project/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/www/index.html b/lib/cordova-blackberry/bin/templates/project/www/index.html
index f083790..6b53abc 100644
--- a/lib/cordova-blackberry/bin/templates/project/www/index.html
+++ b/lib/cordova-blackberry/bin/templates/project/www/index.html
@@ -18,8 +18,8 @@
     under the License.
 -->
 <html>
-    <head>      
-        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <head>
+        <meta charset="utf-8" />
         <meta name="format-detection" content="telephone=no" />
         <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" />


[37/43] git commit: [CB-3228] Fix 'cordova build blackberry' to use cordova.js

Posted by an...@apache.org.
[CB-3228] Fix 'cordova build blackberry' to use cordova.js


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

Branch: refs/heads/master
Commit: dac8583dadea1ad96f7960450af7b592af54773c
Parents: e6ca7df
Author: Michael Brooks <mi...@michaelbrooks.ca>
Authored: Fri Apr 26 16:19:16 2013 -0700
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu May 9 15:56:00 2013 -0700

----------------------------------------------------------------------
 lib/cordova-blackberry/bin/create |    2 +-
 src/metadata/blackberry_parser.js |   62 ++++++++++---------------------
 2 files changed, 21 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/dac8583d/lib/cordova-blackberry/bin/create
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/create b/lib/cordova-blackberry/bin/create
index 54903b8..ca84dc8 100755
--- a/lib/cordova-blackberry/bin/create
+++ b/lib/cordova-blackberry/bin/create
@@ -93,7 +93,7 @@ then
     fi
     
 	echo "Creating BlackBerry project..."
-	(cd "$BUILD_PATH" && "$ANT" create -Dproject.path="$PROJECT_PATH" &> /dev/null )
+	("$ANT" create -Dproject.path="$PROJECT_PATH" -f "$BUILD_PATH/build.xml" &> /dev/null)
     # interpolate the activity and package into config.xml
     echo "Updating config.xml ..."
     replace "s/__NAME__/${NAME}/g" "$MANIFEST_PATH"

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/dac8583d/src/metadata/blackberry_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/blackberry_parser.js b/src/metadata/blackberry_parser.js
index 97cdd59..3d8b578 100644
--- a/src/metadata/blackberry_parser.js
+++ b/src/metadata/blackberry_parser.js
@@ -64,7 +64,6 @@ module.exports.prototype = {
         self.update_from_config(cfg);
         self.update_www();
         self.update_overrides();
-        self.update_staging();
         util.deleteSvnFolders(this.www_dir());
 
         // Do we have BB config?
@@ -90,63 +89,42 @@ module.exports.prototype = {
         return path.join(this.path, 'www');
     },
 
-    staging_dir: function() {
-        return path.join(this.path, '.staging', 'www');
-    },
-
-    config_xml:function(){
-        return this.config_path;
-    },
-
     update_www:function() {
         var projectRoot = util.isCordova(this.path);
-        var www = util.projectWww(projectRoot);
+        var www = path.join(projectRoot, 'www');
         var platformWww = this.www_dir();
 
-        var finalWww = path.join(this.path, 'finalwww');
-        shell.mkdir('-p', finalWww);
-
-        // replace stock bb app contents with app contents. 
-        // to keep:
-        //        - config.xml
-        //        - cordova.js
-        //        - ext*
-        //        - plugins.xml
-        //        - res
-        shell.cp('-f', path.join(platformWww, 'config.xml'), finalWww);
-        shell.cp('-f', path.join(platformWww, 'cordova-*.js'), finalWww);
-        shell.cp('-f', path.join(platformWww, 'plugins.xml'), finalWww);
-        shell.cp('-rf', path.join(platformWww, 'ext*'), finalWww);
-        shell.cp('-rf', path.join(platformWww, 'res'), finalWww);
-
-        // Copy everything over from platform-agnostic www.
-        shell.cp('-rf', path.join(www, '*'), finalWww);
-
-        // Delete the old platform www, and move the final project over
-        shell.rm('-rf', platformWww);
-        shell.mv(finalWww, platformWww);
+        // remove the stock www folder
+        shell.rm('-rf', this.www_dir());
+
+        // copy over project www assets
+        shell.cp('-rf', www, this.path);
+
+        // add cordova.js
+        shell.cp('-f', path.join(util.libDirectory, 'cordova-blackberry', 'javascript', 'cordova.blackberry.js'), path.join(this.www_dir(), 'cordova.js'));
+
+        // add webworks ext directories
+        shell.cp('-rf', path.join(util.libDirectory, 'cordova-blackberry', 'framework', 'ext*'), this.www_dir());
 
+        // add config.xml
+        // @TODO should use project www/config.xml but it must use BBWP elements
+        shell.cp('-f', path.join(util.libDirectory, 'cordova-blackberry', 'bin', 'templates', 'project', 'www', 'config.xml'), this.www_dir());
+
+        // add res/
+        // @TODO remove this when config.xml is generalized
+        shell.cp('-rf', path.join(util.libDirectory, 'cordova-blackberry', 'bin', 'templates', 'project', 'www', 'res'), this.www_dir());
     },
 
     // update the overrides folder into the www folder
     update_overrides:function() {
         var projectRoot = util.isCordova(this.path);
-        var merges_path = path.join(util.appDir(projectRoot), 'merges', 'blackberry');
+        var merges_path = path.join(projectRoot, 'merges', 'blackberry');
         if (fs.existsSync(merges_path)) {
             var overrides = path.join(merges_path, '*');
             shell.cp('-rf', overrides, this.www_dir());
         }
     },
 
-    // update the overrides folder into the www folder
-    update_staging:function() {
-        var projectRoot = util.isCordova(this.path);
-        if (fs.existsSync(this.staging_dir())) {
-            var staging = path.join(this.staging_dir(), '*');
-            shell.cp('-rf', staging, this.www_dir());
-        }
-    },
-
     write_project_properties:function() {
         // TODO: eventually support all blackberry sub-platforms
         var projectRoot = util.isCordova(this.path);


[27/43] git commit: [#3050] Add cordova.platform.support(name, callback).

Posted by an...@apache.org.
[#3050] Add cordova.platform.support(name, callback).


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

Branch: refs/heads/master
Commit: ab582577971b2a1cc114c4a9533d187cb878ff3a
Parents: 56e4563
Author: Michael Brooks <mi...@michaelbrooks.ca>
Authored: Wed Apr 17 15:11:11 2013 -0600
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu May 9 14:26:06 2013 -0700

----------------------------------------------------------------------
 spec/platform.spec.js |   59 ++++++++++++++++++++++++++++++++++++++++++++
 src/platform.js       |   37 ++++++++++++++++++++++++++-
 2 files changed, 94 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ab582577/spec/platform.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform.spec.js b/spec/platform.spec.js
index c2c173f..c5d9f09 100644
--- a/spec/platform.spec.js
+++ b/spec/platform.spec.js
@@ -278,3 +278,62 @@ describe('platform command', function() {
         });
     });
 });
+
+describe('platform.supports(name, callback)', function() {
+    var androidParser = require('../src/metadata/android_parser');
+
+    beforeEach(function() {
+        spyOn(androidParser, 'check_requirements');
+    });
+
+    it('should require a platform name', function() {
+        expect(function() {
+            cordova.platform.supports(undefined, function(e){});
+        }).toThrow();
+    });
+
+    it('should require a callback function', function() {
+        expect(function() {
+            cordova.platform.supports('android', undefined);
+        }).toThrow();
+    });
+
+    describe('when platform is unknown', function() {
+        it('should trigger callback with false', function(done) {
+            cordova.platform.supports('windows-3.1', function(e) {
+                expect(e).toEqual(jasmine.any(Error));
+                done();
+            });
+        });
+    });
+
+    describe('when platform is supported', function() {
+        beforeEach(function() {
+            androidParser.check_requirements.andCallFake(function(callback) {
+                callback(null);
+            });
+        });
+
+        it('should trigger callback without error', function(done) {
+            cordova.platform.supports('android', function(e) {
+                expect(e).toBeNull();
+                done();
+            });
+        });
+    });
+
+    describe('when platform is unsupported', function() {
+        beforeEach(function() {
+            androidParser.check_requirements.andCallFake(function(callback) {
+                callback(new Error('could not find the android sdk'));
+            });
+        });
+
+        it('should trigger callback with error', function(done) {
+            cordova.platform.supports('android', function(e) {
+                expect(e).toEqual(jasmine.any(Error));
+                done();
+            });
+        });
+    });
+});

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ab582577/src/platform.js
----------------------------------------------------------------------
diff --git a/src/platform.js b/src/platform.js
index 1e51c6c..0e31303 100644
--- a/src/platform.js
+++ b/src/platform.js
@@ -79,9 +79,9 @@ module.exports = function platform(command, targets, callback) {
                 }
 
                 // Make sure we have minimum requirements to work with specified platform
-                require('./metadata/' + target + '_parser').check_requirements(function(err) {
+                module.exports.supports(target, function(err) {
                     if (err) {
-                        throw new Error('Your system does not meet the requirements to create ' + target + ' projects: ' + err);
+                        throw new Error('Your system does not meet the requirements to create ' + target + ' projects: ' + err.message);
                     } else {
                         // Create a platform app using the ./bin/create scripts that exist in each repo.
                         // TODO: eventually refactor to allow multiple versions to be created.
@@ -134,3 +134,36 @@ module.exports = function platform(command, targets, callback) {
             throw new Error('Unrecognized command "' + command + '". Use either `add`, `remove`, or `list`.');
     }
 };
+
+/**
+ * Check Platform Support.
+ *
+ * Options:
+ *
+ *   - {String} `name` of the platform to test.
+ *   - {Function} `callback` is triggered with the answer.
+ *     - {Error} `e` null when a platform is supported otherwise describes error.
+ */
+
+module.exports.supports = function(name, callback) {
+    // required parameters
+    if (!name) throw new Error('requires a platform name parameter');
+    if (!callback) throw new Error('requires a callback parameter');
+
+    // look up platform meta-data parser
+    var platformParser = parsers[name];
+    if (!platformParser) {
+        callback(new Error(util.format('"%s" platform does not exist', name)));
+        return;
+    }
+
+    // check for platform support
+    platformParser.check_requirements(function(e) {
+        // typecast String to Error
+        e = (e instanceof String) ? new Error(e) : e;
+        // typecast false Boolean to null
+        e = (e) ? e : null;
+
+        callback(e);
+    });
+};


[33/43] Version 2.7.0-rc.1

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m
index 90c96d2..93cafb8 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m
@@ -20,8 +20,15 @@
 #import "CDVJpegHeaderWriter.h"
 #include "CDVExif.h"
 
-// tag info shorthand, tagno: tag number, typecode: data type:, components: number of components
+/* macros for tag info shorthand:
+   tagno        : tag number
+   typecode     : data type
+   components   : number of components
+   appendString (TAGINF_W_APPEND only) : string to append to data
+      Exif date data format include an extra 0x00 to the end of the data
+ */
 #define TAGINF(tagno, typecode, components) [NSArray arrayWithObjects: tagno, typecode, components, nil]
+#define TAGINF_W_APPEND(tagno, typecode, components, appendString) [NSArray arrayWithObjects: tagno, typecode, components, appendString, nil]
 
 const uint mJpegId = 0xffd8; // JPEG format marker
 const uint mExifMarker = 0xffe1; // APP1 jpeg header marker
@@ -38,7 +45,7 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
     // supported tags for exif IFD
     IFD0TagFormatDict = [[NSDictionary alloc] initWithObjectsAndKeys:
                   //      TAGINF(@"010e", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"ImageDescription",
-                        TAGINF(@"0132", [NSNumber numberWithInt:EDT_ASCII_STRING], @20), @"DateTime",
+                        TAGINF_W_APPEND(@"0132", [NSNumber numberWithInt:EDT_ASCII_STRING], @20, @"00"), @"DateTime",
                         TAGINF(@"010f", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Make",
                         TAGINF(@"0110", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Model",
                         TAGINF(@"0131", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Software",
@@ -68,8 +75,8 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
                            //TAGINF(@"9202",[NSNumber numberWithInt:EDT_URATIONAL],@1), @"ApertureValue",
                            //TAGINF(@"9203",[NSNumber numberWithInt:EDT_SRATIONAL],@1), @"BrightnessValue",
                            TAGINF(@"a001",[NSNumber numberWithInt:EDT_USHORT],@1), @"ColorSpace",
-                           TAGINF(@"9004",[NSNumber numberWithInt:EDT_ASCII_STRING],@20), @"DateTimeDigitized",
-                           TAGINF(@"9003",[NSNumber numberWithInt:EDT_ASCII_STRING],@20), @"DateTimeOriginal",
+                           TAGINF_W_APPEND(@"9004",[NSNumber numberWithInt:EDT_ASCII_STRING],@20,@"00"), @"DateTimeDigitized",
+                           TAGINF_W_APPEND(@"9003",[NSNumber numberWithInt:EDT_ASCII_STRING],@20,@"00"), @"DateTimeOriginal",
                            TAGINF(@"a402", [NSNumber numberWithInt:EDT_USHORT], @1), @"ExposureMode",
                            TAGINF(@"8822", [NSNumber numberWithInt:EDT_USHORT], @1), @"ExposureProgram",
                            //TAGINF(@"829a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"ExposureTime",
@@ -167,12 +174,14 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
     NSString * tiffheader = @"4d4d002a";
     //first IFD offset from the Tiff header to IFD0. Since we are writing it, we know it's address 0x08
     NSString * ifd0offset = @"00000008";
+    // current offset to next data area
+    int currentDataOffset = 0;
     
     //data labeled as TIFF in UIImagePickerControllerMediaMetaData is part of the EXIF IFD0 portion of APP1
-    exifIFD = [self createExifIFDFromDict: [datadict objectForKey:@"{TIFF}"] withFormatDict: IFD0TagFormatDict isIFD0:YES];
+    exifIFD = [self createExifIFDFromDict: [datadict objectForKey:@"{TIFF}"] withFormatDict: IFD0TagFormatDict isIFD0:YES currentDataOffset:&currentDataOffset];
 
     //data labeled as EXIF in UIImagePickerControllerMediaMetaData is part of the EXIF Sub IFD portion of APP1
-    subExifIFD = [self createExifIFDFromDict: [datadict objectForKey:@"{Exif}"] withFormatDict: SubIFDTagFormatDict isIFD0:NO];
+    subExifIFD = [self createExifIFDFromDict: [datadict objectForKey:@"{Exif}"] withFormatDict: SubIFDTagFormatDict isIFD0:NO currentDataOffset:&currentDataOffset];
     /*
     NSLog(@"SUB EXIF IFD %@  WITH SIZE: %d",exifIFD,[exifIFD length]);
     
@@ -192,8 +201,11 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
 }
 
 // returns hex string representing a valid exif information file directory constructed from the datadict and formatdict
-- (NSString*) createExifIFDFromDict : (NSDictionary*) datadict withFormatDict : (NSDictionary*) formatdict isIFD0 : (BOOL) ifd0flag {
-    NSArray * datakeys = [datadict allKeys]; // all known data keys 
+- (NSString*) createExifIFDFromDict : (NSDictionary*) datadict
+                     withFormatDict : (NSDictionary*) formatdict
+                             isIFD0 : (BOOL) ifd0flag
+                  currentDataOffset : (int*) dataoffset {
+    NSArray * datakeys = [datadict allKeys]; // all known data keys
     NSArray * knownkeys = [formatdict  allKeys]; // only keys in knowkeys are considered for entry in this IFD
     NSMutableArray * ifdblock = [[NSMutableArray alloc] initWithCapacity: [datadict count]]; // all ifd entries
     NSMutableArray * ifddatablock = [[NSMutableArray alloc] initWithCapacity: [datadict count]]; // data block entries
@@ -225,13 +237,13 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
     NSMutableString * exifstr = [[NSMutableString alloc] initWithCapacity: [ifdblock count] * 24];
     NSMutableString * dbstr = [[NSMutableString alloc] initWithCapacity: 100];
     
-    int addr=0; // current offset/address in datablock
+    int addr=*dataoffset; // current offset/address in datablock
     if (ifd0flag) {
         // calculate offset to datablock based on ifd file entry count
-        addr = 14+(12*([ifddatablock count]+1)); // +1 for tag 0x8769, exifsubifd offset
+        addr += 14+(12*([ifddatablock count]+1)); // +1 for tag 0x8769, exifsubifd offset
     } else {
-        // same calculation as above, but no exifsubifd offset
-        addr = 14+12*[ifddatablock count];
+        // current offset + numSubIFDs (2-bytes) + 12*numSubIFDs + endMarker (4-bytes)
+        addr += 2+(12*[ifddatablock count])+4;
     }
     
     for (int i = 0; i < [ifdblock count]; i++) {
@@ -244,8 +256,14 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
             [exifstr appendFormat : @"%@%@", entry, data];
         } else {
             [exifstr appendFormat : @"%@%08x", entry, addr];
-            [dbstr appendFormat: @"%@", data]; 
+            [dbstr appendFormat: @"%@", data];
             addr+= [data length] / 2;
+            /*
+            NSLog(@"=====data-length[%i]=======",[data length]);
+            NSLog(@"addr-offset[%i]",addr);
+            NSLog(@"entry[%@]",entry);
+            NSLog(@"data[%@]",data);
+             */
         }
     }
     
@@ -258,7 +276,8 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
         [self appendExifOffsetTagTo: exifstr
                         withOffset : offset];
         entrycount++;
-    } 
+    }
+    *dataoffset = addr;
     return [[NSString alloc] initWithFormat: @"%04x%@%@%@",
             entrycount,
             exifstr,
@@ -307,6 +326,7 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
     NSMutableString * datastr = nil;
     NSNumber * tmp = nil;
     NSNumber * formatcode = [dataformat objectAtIndex:1];
+    NSUInteger formatItemsCount = [dataformat count];
     NSNumber * num = @0;
     NSNumber * denom = @0;
     
@@ -318,6 +338,11 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
             for (int i = 0; i < [data length]; i++) {
                 [datastr appendFormat:@"%02x",[data characterAtIndex:i]];
             }
+            if (formatItemsCount > 3) {
+                // We have additional data to append.
+                // currently used by Date format to append final 0x00 but can be used by other data types as well in the future
+                [datastr appendString:[dataformat objectAtIndex:3]];
+            }
             if ([datastr length] < 8) {
                 NSString * format = [NSString stringWithFormat:@"%%0%dd", 8 - [datastr length]];
                 [datastr appendFormat:format,0];

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h b/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h
index 6e25a27..33ba1c4 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h
@@ -23,10 +23,10 @@
 #import "NSMutableArray+QueueAdditions.h"
 #import "CDVCommandDelegate.h"
 
-NSString* const CDVPageDidLoadNotification;
-NSString* const CDVPluginHandleOpenURLNotification;
-NSString* const CDVPluginResetNotification;
-NSString* const CDVLocalNotification;
+extern NSString* const CDVPageDidLoadNotification;
+extern NSString* const CDVPluginHandleOpenURLNotification;
+extern NSString* const CDVPluginResetNotification;
+extern NSString* const CDVLocalNotification;
 
 @interface CDVPlugin : NSObject {}
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVSound.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVSound.m b/lib/cordova-ios/CordovaLib/Classes/CDVSound.m
index 88fbbd6..71eab59 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVSound.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVSound.m
@@ -273,6 +273,9 @@
     } else {
         audioFile = [[self soundCache] objectForKey:mediaId];
         audioFile.volume = volume;
+        if (audioFile.player) {
+            audioFile.player.volume = [volume floatValue];
+        }
         [[self soundCache] setObject:audioFile forKey:mediaId];
     }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVTimer.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVTimer.h b/lib/cordova-ios/CordovaLib/Classes/CDVTimer.h
new file mode 100644
index 0000000..6d31593
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVTimer.h
@@ -0,0 +1,27 @@
+/*
+ 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+@interface CDVTimer : NSObject
+
++ (void)start:(NSString*)name;
++ (void)stop:(NSString*)name;
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVTimer.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVTimer.m b/lib/cordova-ios/CordovaLib/Classes/CDVTimer.m
new file mode 100644
index 0000000..784e94d
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVTimer.m
@@ -0,0 +1,123 @@
+/*
+ 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.
+ */
+
+#import "CDVTimer.h"
+
+#pragma mark CDVTimerItem
+
+@interface CDVTimerItem : NSObject
+
+@property (nonatomic, strong) NSString* name;
+@property (nonatomic, strong) NSDate* started;
+@property (nonatomic, strong) NSDate* ended;
+
+- (void)log;
+
+@end
+
+@implementation CDVTimerItem
+
+- (void)log
+{
+    NSLog(@"[CDVTimer][%@] %fms", self.name, [self.ended timeIntervalSinceDate:self.started] * 1000.0);
+}
+
+@end
+
+#pragma mark CDVTimer
+
+@interface CDVTimer ()
+
+@property (nonatomic, strong) NSMutableDictionary* items;
+
+@end
+
+@implementation CDVTimer
+
+#pragma mark object methods
+
+- (id)init
+{
+    if (self = [super init]) {
+        self.items = [NSMutableDictionary dictionaryWithCapacity:6];
+    }
+
+    return self;
+}
+
+- (void)add:(NSString*)name
+{
+    if ([self.items objectForKey:[name lowercaseString]] == nil) {
+        CDVTimerItem* item = [CDVTimerItem new];
+        item.name = name;
+        item.started = [NSDate new];
+        [self.items setObject:item forKey:[name lowercaseString]];
+    } else {
+        NSLog(@"Timer called '%@' already exists.", name);
+    }
+}
+
+- (void)remove:(NSString*)name
+{
+    CDVTimerItem* item = [self.items objectForKey:[name lowercaseString]];
+
+    if (item != nil) {
+        item.ended = [NSDate new];
+        [item log];
+        [self.items removeObjectForKey:[name lowercaseString]];
+    } else {
+        NSLog(@"Timer called '%@' does not exist.", name);
+    }
+}
+
+- (void)removeAll
+{
+    [self.items removeAllObjects];
+}
+
+#pragma mark class methods
+
++ (void)start:(NSString*)name
+{
+    [[CDVTimer sharedInstance] add:name];
+}
+
++ (void)stop:(NSString*)name
+{
+    [[CDVTimer sharedInstance] remove:name];
+}
+
++ (void)clearAll
+{
+    [[CDVTimer sharedInstance] removeAll];
+}
+
++ (CDVTimer*)sharedInstance
+{
+    static dispatch_once_t pred = 0;
+    __strong static CDVTimer* _sharedObject = nil;
+
+    dispatch_once(&pred, ^{
+            _sharedObject = [[self alloc] init];
+        });
+
+    return _sharedObject;
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m b/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m
index c7ad01b..94f4552 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m
@@ -128,7 +128,7 @@
 
 - (void)keyboardWillShowOrHide:(NSNotification*)notif
 {
-    if (![@"true" isEqualToString:self.settings[@"KeyboardShrinksView"]]) {
+    if (![@"true" isEqualToString : self.settings[@"KeyboardShrinksView"]]) {
         return;
     }
     BOOL showEvent = [notif.name isEqualToString:UIKeyboardWillShowNotification];
@@ -290,18 +290,18 @@
         [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillShowNotification
                                                           object:nil
                                                            queue:[NSOperationQueue mainQueue]
-                                                      usingBlock:^(NSNotification * notification) {
-                // we can't hide it here because the accessory bar hasn't been created yet, so we delay on the queue
-                [weakSelf performSelector:@selector(hideKeyboardFormAccessoryBar) withObject:nil afterDelay:0];
-            }];
+                                                      usingBlock:^(NSNotification* notification) {
+            // we can't hide it here because the accessory bar hasn't been created yet, so we delay on the queue
+            [weakSelf performSelector:@selector(hideKeyboardFormAccessoryBar) withObject:nil afterDelay:0];
+        }];
     }
 
     /*
      * Fire up CDVLocalStorage to work-around WebKit storage limitations: on all iOS 5.1+ versions for local-only backups, but only needed on iOS 5.1 for cloud backup.
      */
-    if (IsAtLeastiOSVersion (@"5.1") && (([backupWebStorageType isEqualToString:@"local"]) ||
-            ([backupWebStorageType isEqualToString:@"cloud"] && !IsAtLeastiOSVersion (@"6.0")))) {
-        [self registerPlugin:[[CDVLocalStorage alloc] initWithWebView:self.webView] withClassName:NSStringFromClass ([CDVLocalStorage class])];
+    if (IsAtLeastiOSVersion(@"5.1") && (([backupWebStorageType isEqualToString:@"local"]) ||
+        ([backupWebStorageType isEqualToString:@"cloud"] && !IsAtLeastiOSVersion(@"6.0")))) {
+        [self registerPlugin:[[CDVLocalStorage alloc] initWithWebView:self.webView] withClassName:NSStringFromClass([CDVLocalStorage class])];
     }
 
     /*
@@ -342,7 +342,7 @@
     /*
      * iOS 6.0 UIWebView properties
      */
-    if (IsAtLeastiOSVersion (@"6.0")) {
+    if (IsAtLeastiOSVersion(@"6.0")) {
         BOOL keyboardDisplayRequiresUserAction = YES; // KeyboardDisplayRequiresUserAction - defaults to YES
         if ([self.settings objectForKey:@"KeyboardDisplayRequiresUserAction"] != nil) {
             if ([self.settings objectForKey:@"KeyboardDisplayRequiresUserAction"]) {
@@ -368,8 +368,16 @@
         }
     }
 
-    for (NSString* pluginName in self.startupPluginNames) {
-        [self getCommandInstance:pluginName];
+    if ([self.startupPluginNames count] > 0) {
+        [CDVTimer start:@"TotalPluginStartup"];
+
+        for (NSString* pluginName in self.startupPluginNames) {
+            [CDVTimer start:pluginName];
+            [self getCommandInstance:pluginName];
+            [CDVTimer stop:pluginName];
+        }
+
+        [CDVTimer stop:@"TotalPluginStartup"];
     }
 
     // TODO: Remove this explicit instantiation once we move to cordova-CLI.
@@ -379,16 +387,16 @@
 
     // /////////////////
     [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) {
-            _userAgentLockToken = lockToken;
-            [CDVUserAgentUtil setUserAgent:self.userAgent lockToken:lockToken];
-            if (!loadErr) {
-                NSURLRequest* appReq = [NSURLRequest requestWithURL:appURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
-                [self.webView loadRequest:appReq];
-            } else {
-                NSString* html = [NSString stringWithFormat:@"<html><body> %@ </body></html>", loadErr];
-                [self.webView loadHTMLString:html baseURL:nil];
-            }
-        }];
+        _userAgentLockToken = lockToken;
+        [CDVUserAgentUtil setUserAgent:self.userAgent lockToken:lockToken];
+        if (!loadErr) {
+            NSURLRequest* appReq = [NSURLRequest requestWithURL:appURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0];
+            [self.webView loadRequest:appReq];
+        } else {
+            NSString* html = [NSString stringWithFormat:@"<html><body> %@ </body></html>", loadErr];
+            [self.webView loadHTMLString:html baseURL:nil];
+        }
+    }];
 }
 
 - (void)hideKeyboardFormAccessoryBar
@@ -607,12 +615,6 @@
     // It's safe to release the lock even if this is just a sub-frame that's finished loading.
     [CDVUserAgentUtil releaseLock:&_userAgentLockToken];
 
-    // The .onNativeReady().fire() will work when cordova.js is already loaded.
-    // The _nativeReady = true; is used when this is run before cordova.js is loaded.
-    NSString* nativeReady = @"try{cordova.require('cordova/channel').onNativeReady.fire();}catch(e){window._nativeReady = true;}";
-    // Don't use [commandDelegate evalJs] here since it relies on cordova.js being loaded already.
-    [self.webView stringByEvaluatingJavaScriptFromString:nativeReady];
-
     /*
      * Hide the Top Activity THROBBER in the Battery Bar
      */
@@ -783,7 +785,7 @@
 
     id obj = [self.pluginObjects objectForKey:className];
     if (!obj) {
-        obj = [[NSClassFromString (className)alloc] initWithWebView:webView];
+        obj = [[NSClassFromString(className)alloc] initWithWebView:webView];
 
         if (obj != nil) {
             [self registerPlugin:obj withClassName:className];

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.h b/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.h
index 8a89a22..a4d78bd 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.h
@@ -30,6 +30,7 @@
     NSInteger _loadCount;
     NSInteger _state;
     NSInteger _curLoadToken;
+    NSInteger _loadStartPollCount;
 }
 
 - (id)initWithDelegate:(NSObject <UIWebViewDelegate>*)delegate;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m b/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m
index a72bfb9..fd9c032 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m
@@ -17,14 +17,77 @@
  under the License.
  */
 
+//
+// Testing shows:
+//
+// In all cases, webView.request.URL is the previous page's URL (or empty) during the didStartLoad callback.
+// When loading a page with a redirect:
+// 1. shouldStartLoading (requestURL is target page)
+// 2. didStartLoading
+// 3. shouldStartLoading (requestURL is redirect target)
+// 4. didFinishLoad (request.URL is redirect target)
+//
+// Note the lack of a second didStartLoading **
+//
+// When loading a page with iframes:
+// 1. shouldStartLoading (requestURL is main page)
+// 2. didStartLoading
+// 3. shouldStartLoading (requestURL is one of the iframes)
+// 4. didStartLoading
+// 5. didFinishLoad
+// 6. didFinishLoad
+//
+// Note there is no way to distinguish which didFinishLoad maps to which didStartLoad **
+//
+// Loading a page by calling window.history.go(-1):
+// 1. didStartLoading
+// 2. didFinishLoad
+//
+// Note the lack of a shouldStartLoading call **
+// Actually - this is fixed on iOS6. iOS6 has a shouldStart. **
+//
+// Loading a page by calling location.reload()
+// 1. shouldStartLoading
+// 2. didStartLoading
+// 3. didFinishLoad
+//
+// Loading a page with an iframe that fails to load:
+// 1. shouldStart (main page)
+// 2. didStart
+// 3. shouldStart (iframe)
+// 4. didStart
+// 5. didFailWithError
+// 6. didFinish
+//
+// Loading a page with an iframe that fails to load due to an invalid URL:
+// 1. shouldStart (main page)
+// 2. didStart
+// 3. shouldStart (iframe)
+// 5. didFailWithError
+// 6. didFinish
+//
+// This case breaks our logic since there is a missing didStart. To prevent this,
+// we check URLs in shouldStart and return NO if they are invalid.
+//
+// Loading a page with an invalid URL
+// 1. shouldStart (main page)
+// 2. didFailWithError
+//
+// TODO: Record order when page is re-navigated before the first navigation finishes.
+//
+
 #import "CDVWebViewDelegate.h"
 #import "CDVAvailability.h"
 
+// #define VerboseLog NSLog
+#define VerboseLog(...) do {} while (0)
+
 typedef enum {
-    STATE_NORMAL,
-    STATE_SHOULD_LOAD_MISSING,
-    STATE_WAITING_FOR_START,
-    STATE_WAITING_FOR_FINISH
+    STATE_IDLE,
+    STATE_WAITING_FOR_LOAD_START,
+    STATE_WAITING_FOR_LOAD_FINISH,
+    STATE_IOS5_POLLING_FOR_LOAD_START,
+    STATE_IOS5_POLLING_FOR_LOAD_FINISH
 } State;
 
 @implementation CDVWebViewDelegate
@@ -35,7 +98,7 @@ typedef enum {
     if (self != nil) {
         _delegate = delegate;
         _loadCount = -1;
-        _state = STATE_NORMAL;
+        _state = STATE_IDLE;
     }
     return self;
 }
@@ -62,31 +125,41 @@ typedef enum {
 
 - (void)pollForPageLoadStart:(UIWebView*)webView
 {
-    if ((_state != STATE_WAITING_FOR_START) && (_state != STATE_SHOULD_LOAD_MISSING)) {
+    if (_state != STATE_IOS5_POLLING_FOR_LOAD_START) {
         return;
     }
     if (![self isJsLoadTokenSet:webView]) {
-        _state = STATE_WAITING_FOR_FINISH;
+        VerboseLog(@"Polled for page load start. result = YES!");
+        _state = STATE_IOS5_POLLING_FOR_LOAD_FINISH;
         [self setLoadToken:webView];
         if ([_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
             [_delegate webViewDidStartLoad:webView];
         }
         [self pollForPageLoadFinish:webView];
+    } else {
+        VerboseLog(@"Polled for page load start. result = NO");
+        // Poll only for 1 second, and then fall back on checking only when delegate methods are called.
+        ++_loadStartPollCount;
+        if (_loadStartPollCount < (1000 * .05)) {
+            [self performSelector:@selector(pollForPageLoadStart:) withObject:webView afterDelay:.05];
+        }
     }
 }
 
 - (void)pollForPageLoadFinish:(UIWebView*)webView
 {
-    if (_state != STATE_WAITING_FOR_FINISH) {
+    if (_state != STATE_IOS5_POLLING_FOR_LOAD_FINISH) {
         return;
     }
     if ([self isPageLoaded:webView]) {
-        _state = STATE_SHOULD_LOAD_MISSING;
+        VerboseLog(@"Polled for page load finish. result = YES!");
+        _state = STATE_IDLE;
         if ([_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
             [_delegate webViewDidFinishLoad:webView];
         }
     } else {
-        [self performSelector:@selector(pollForPageLoaded) withObject:webView afterDelay:50];
+        VerboseLog(@"Polled for page load finish. result = NO");
+        [self performSelector:@selector(pollForPageLoadFinish:) withObject:webView afterDelay:.05];
     }
 }
 
@@ -98,73 +171,163 @@ typedef enum {
         shouldLoad = [_delegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
     }
 
+    VerboseLog(@"webView shouldLoad=%d (before) state=%d loadCount=%d URL=%@", shouldLoad, _state, _loadCount, request.URL);
+
     if (shouldLoad) {
         BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]];
         if (isTopLevelNavigation) {
-            _loadCount = 0;
-            _state = STATE_NORMAL;
+            switch (_state) {
+                case STATE_WAITING_FOR_LOAD_FINISH:
+                    // Redirect case.
+                    // We expect loadCount == 1.
+                    if (_loadCount != 1) {
+                        NSLog(@"CDVWebViewDelegate: Detected redirect when loadCount=%d", _loadCount);
+                    }
+                    break;
+
+                case STATE_IDLE:
+                case STATE_IOS5_POLLING_FOR_LOAD_START:
+                    // Page navigation start.
+                    _loadCount = 0;
+                    _state = STATE_WAITING_FOR_LOAD_START;
+                    break;
+
+                default:
+                    NSLog(@"CDVWebViewDelegate: Navigation started when state=%d", _state);
+                    _loadCount = 0;
+                    _state = STATE_WAITING_FOR_LOAD_START;
+                    if ([_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
+                        [_delegate webView:webView didFailLoadWithError:nil];
+                    }
+            }
+        } else {
+            // Deny invalid URLs so that we don't get the case where we go straight from
+            // webViewShouldLoad -> webViewDidFailLoad (messes up _loadCount).
+            shouldLoad = shouldLoad && [NSURLConnection canHandleRequest:request];
         }
+        VerboseLog(@"webView shouldLoad=%d (after) isTopLevelNavigation=%d state=%d loadCount=%d", shouldLoad, isTopLevelNavigation, _state, _loadCount);
     }
     return shouldLoad;
 }
 
 - (void)webViewDidStartLoad:(UIWebView*)webView
 {
-    if (_state == STATE_NORMAL) {
-        if (_loadCount == 0) {
-            if ([_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
-                [_delegate webViewDidStartLoad:webView];
+    VerboseLog(@"webView didStartLoad (before). state=%d loadCount=%d", _state, _loadCount);
+    BOOL fireCallback = NO;
+    switch (_state) {
+        case STATE_IDLE:
+            if (IsAtLeastiOSVersion(@"6.0")) {
+                break;
             }
-            _loadCount += 1;
-        } else if (_loadCount > 0) {
-            _loadCount += 1;
-        } else if (!IsAtLeastiOSVersion(@"6.0")) {
             // If history.go(-1) is used pre-iOS6, the shouldStartLoadWithRequest function is not called.
             // Without shouldLoad, we can't distinguish an iframe from a top-level navigation.
             // We could try to distinguish using [UIWebView canGoForward], but that's too much complexity,
             // and would work only on the first time it was used.
 
             // Our work-around is to set a JS variable and poll until it disappears (from a naviagtion).
-            _state = STATE_WAITING_FOR_START;
+            _state = STATE_IOS5_POLLING_FOR_LOAD_START;
+            _loadStartPollCount = 0;
             [self setLoadToken:webView];
-        }
-    } else {
-        [self pollForPageLoadStart:webView];
-        [self pollForPageLoadFinish:webView];
+            [self pollForPageLoadStart:webView];
+            break;
+
+        case STATE_WAITING_FOR_LOAD_START:
+            if (_loadCount != 0) {
+                NSLog(@"CDVWebViewDelegate: Unexpected loadCount in didStart. count=%d", _loadCount);
+            }
+            fireCallback = YES;
+            _state = STATE_WAITING_FOR_LOAD_FINISH;
+            _loadCount = 1;
+            break;
+
+        case STATE_WAITING_FOR_LOAD_FINISH:
+            _loadCount += 1;
+            break;
+
+        case STATE_IOS5_POLLING_FOR_LOAD_START:
+            [self pollForPageLoadStart:webView];
+            break;
+
+        case STATE_IOS5_POLLING_FOR_LOAD_FINISH:
+            [self pollForPageLoadFinish:webView];
+            break;
+
+        default:
+            NSLog(@"CDVWebViewDelegate: Unexpected didStart with state=%d loadCount=%d", _state, _loadCount);
+    }
+    VerboseLog(@"webView didStartLoad (after). state=%d loadCount=%d fireCallback=%d", _state, _loadCount, fireCallback);
+    if (fireCallback && [_delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
+        [_delegate webViewDidStartLoad:webView];
     }
 }
 
 - (void)webViewDidFinishLoad:(UIWebView*)webView
 {
-    if (_state == STATE_NORMAL) {
-        if (_loadCount == 1) {
-            if ([_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
-                [_delegate webViewDidFinishLoad:webView];
+    VerboseLog(@"webView didFinishLoad (before). state=%d loadCount=%d", _state, _loadCount);
+    BOOL fireCallback = NO;
+    switch (_state) {
+        case STATE_IDLE:
+            break;
+
+        case STATE_WAITING_FOR_LOAD_START:
+            NSLog(@"CDVWebViewDelegate: Unexpected didFinish while waiting for load start.");
+            break;
+
+        case STATE_WAITING_FOR_LOAD_FINISH:
+            if (_loadCount == 1) {
+                fireCallback = YES;
+                _state = STATE_IDLE;
             }
-            _loadCount = -1;
-        } else if (_loadCount > 1) {
             _loadCount -= 1;
-        }
-    } else {
-        [self pollForPageLoadStart:webView];
-        [self pollForPageLoadFinish:webView];
+            break;
+
+        case STATE_IOS5_POLLING_FOR_LOAD_START:
+            [self pollForPageLoadStart:webView];
+            break;
+
+        case STATE_IOS5_POLLING_FOR_LOAD_FINISH:
+            [self pollForPageLoadFinish:webView];
+            break;
+    }
+    VerboseLog(@"webView didFinishLoad (after). state=%d loadCount=%d fireCallback=%d", _state, _loadCount, fireCallback);
+    if (fireCallback && [_delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
+        [_delegate webViewDidFinishLoad:webView];
     }
 }
 
 - (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error
 {
-    if (_state == STATE_NORMAL) {
-        if (_loadCount == 1) {
-            if ([_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
-                [_delegate webView:webView didFailLoadWithError:error];
+    VerboseLog(@"webView didFailLoad (before). state=%d loadCount=%d", _state, _loadCount);
+    BOOL fireCallback = NO;
+
+    switch (_state) {
+        case STATE_IDLE:
+            break;
+
+        case STATE_WAITING_FOR_LOAD_START:
+            _state = STATE_IDLE;
+            fireCallback = YES;
+            break;
+
+        case STATE_WAITING_FOR_LOAD_FINISH:
+            if (_loadCount == 1) {
+                _state = STATE_IDLE;
+                fireCallback = YES;
             }
             _loadCount = -1;
-        } else if (_loadCount > 1) {
-            _loadCount -= 1;
-        }
-    } else {
-        [self pollForPageLoadStart:webView];
-        [self pollForPageLoadFinish:webView];
+            break;
+
+        case STATE_IOS5_POLLING_FOR_LOAD_START:
+            [self pollForPageLoadStart:webView];
+            break;
+
+        case STATE_IOS5_POLLING_FOR_LOAD_FINISH:
+            [self pollForPageLoadFinish:webView];
+            break;
+    }
+    VerboseLog(@"webView didFailLoad (after). state=%d loadCount=%d, fireCallback=%d", _state, _loadCount, fireCallback);
+    if (fireCallback && [_delegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) {
+        [_delegate webView:webView didFailLoadWithError:error];
     }
 }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVWhitelist.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVWhitelist.h b/lib/cordova-ios/CordovaLib/Classes/CDVWhitelist.h
index 3741e94..e339dd0 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVWhitelist.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVWhitelist.h
@@ -23,14 +23,11 @@ extern NSString* const kCDVDefaultWhitelistRejectionString;
 
 @interface CDVWhitelist : NSObject
 
-@property (nonatomic, readonly, strong) NSArray* whitelist;
-@property (nonatomic, readonly, strong) NSArray* expandedWhitelist;
-@property (nonatomic, readonly, assign) BOOL allowAll;
 @property (nonatomic, copy) NSString* whitelistRejectionFormatString;
 
 - (id)initWithArray:(NSArray*)array;
-- (BOOL)URLIsAllowed:(NSURL*)url;
 - (BOOL)schemeIsAllowed:(NSString*)scheme;
+- (BOOL)URLIsAllowed:(NSURL*)url;
 - (NSString*)errorStringForURL:(NSURL*)url;
 
 @end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/Classes/CDVWhitelist.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVWhitelist.m b/lib/cordova-ios/CordovaLib/Classes/CDVWhitelist.m
index 77e20ac..db7aa32 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVWhitelist.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVWhitelist.m
@@ -20,12 +20,12 @@
 #import "CDVWhitelist.h"
 
 NSString* const kCDVDefaultWhitelistRejectionString = @"ERROR whitelist rejection: url='%@'";
+NSString* const kCDVDefaultSchemeName = @"cdv-default-scheme";
 
 @interface CDVWhitelist ()
 
 @property (nonatomic, readwrite, strong) NSArray* whitelist;
-@property (nonatomic, readwrite, strong) NSArray* expandedWhitelist;
-@property (nonatomic, readwrite, assign) BOOL allowAll;
+@property (nonatomic, readwrite, strong) NSDictionary* expandedWhitelists;
 
 - (void)processWhitelist;
 
@@ -33,15 +33,14 @@ NSString* const kCDVDefaultWhitelistRejectionString = @"ERROR whitelist rejectio
 
 @implementation CDVWhitelist
 
-@synthesize whitelist, expandedWhitelist, allowAll, whitelistRejectionFormatString;
+@synthesize whitelist, expandedWhitelists, whitelistRejectionFormatString;
 
 - (id)initWithArray:(NSArray*)array
 {
     self = [super init];
     if (self) {
         self.whitelist = array;
-        self.expandedWhitelist = nil;
-        self.allowAll = NO;
+        self.expandedWhitelists = nil;
         self.whitelistRejectionFormatString = kCDVDefaultWhitelistRejectionString;
         [self processWhitelist];
     }
@@ -94,6 +93,17 @@ NSString* const kCDVDefaultWhitelistRejectionString = @"ERROR whitelist rejectio
     }
 }
 
+- (NSString*)extractSchemeFromUrlString:(NSString*)url
+{
+    NSURL* aUrl = [NSURL URLWithString:url];
+
+    if ((aUrl != nil) && ([aUrl scheme] != nil)) { // found scheme
+        return [aUrl scheme];
+    } else {
+        return kCDVDefaultSchemeName;
+    }
+}
+
 - (void)processWhitelist
 {
     if (self.whitelist == nil) {
@@ -101,70 +111,91 @@ NSString* const kCDVDefaultWhitelistRejectionString = @"ERROR whitelist rejectio
         return;
     }
 
-    NSMutableArray* expanded = [NSMutableArray arrayWithCapacity:[self.whitelist count]];
-
-    // iterate through settings ExternalHosts, check for equality
-    NSEnumerator* enumerator = [self.whitelist objectEnumerator];
-    id externalHost = nil;
+    NSMutableDictionary* _expandedWhitelists = [@{kCDVDefaultSchemeName: [NSMutableArray array]} mutableCopy];
 
     // only allow known TLDs (since Aug 23rd 2011), and two character country codes
     // does not match internationalized domain names with non-ASCII characters
     NSString* tld_match = @"(aero|asia|arpa|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|xxx|[a-z][a-z])";
 
-    while (externalHost = [enumerator nextObject]) {
-        NSString* regex = [self extractHostFromUrlString:externalHost];
-        BOOL is_ip = [self isIPv4Address:regex];
+    // iterate through settings ExternalHosts, check for equality
+    for (NSString* externalHost in self.whitelist) {
+        NSString* host = [self extractHostFromUrlString:externalHost];
+        NSString* scheme = [self extractSchemeFromUrlString:externalHost];
 
         // check for single wildcard '*', if found set allowAll to YES
-        if ([regex isEqualToString:@"*"]) {
-            self.allowAll = YES;
-            self.expandedWhitelist = [NSArray arrayWithObject:regex];
-            break;
+        if ([host isEqualToString:@"*"]) {
+            [_expandedWhitelists setObject:[NSArray arrayWithObject:host] forKey:scheme];
+            continue;
+        }
+
+        // if this is the first value for this scheme, create a new entry
+        if ([_expandedWhitelists objectForKey:scheme] == nil) {
+            [_expandedWhitelists setObject:[NSMutableArray array] forKey:scheme];
         }
 
         // starts with wildcard match - we make the first '.' optional (so '*.org.apache.cordova' will match 'org.apache.cordova')
         NSString* prefix = @"*.";
-        if ([regex hasPrefix:prefix]) {
+        if ([host hasPrefix:prefix]) {
             // replace the first two characters '*.' with our regex
-            regex = [regex stringByReplacingCharactersInRange:NSMakeRange(0, [prefix length]) withString:@"(\\s{0}|*.)"]; // the '*' and '.' will be substituted later
+            host = [host stringByReplacingCharactersInRange:NSMakeRange(0, [prefix length]) withString:@"(\\s{0}|*.)"]; // the '*' and '.' will be substituted later
         }
 
         // ends with wildcard match for TLD
-        if (!is_ip && [regex hasSuffix:@".*"]) {
+        if (![self isIPv4Address:host] && [host hasSuffix:@".*"]) {
             // replace * with tld_match
-            regex = [regex stringByReplacingCharactersInRange:NSMakeRange([regex length] - 1, 1) withString:tld_match];
+            host = [host stringByReplacingCharactersInRange:NSMakeRange([host length] - 1, 1) withString:tld_match];
         }
         // escape periods - since '.' means any character in regex
-        regex = [regex stringByReplacingOccurrencesOfString:@"." withString:@"\\."];
+        host = [host stringByReplacingOccurrencesOfString:@"." withString:@"\\."];
         // wildcard is match 1 or more characters (to make it simple, since we are not doing verification whether the hostname is valid)
-        regex = [regex stringByReplacingOccurrencesOfString:@"*" withString:@".*"];
+        host = [host stringByReplacingOccurrencesOfString:@"*" withString:@".*"];
 
-        [expanded addObject:regex];
+        [[_expandedWhitelists objectForKey:scheme] addObject:host];
     }
 
-    self.expandedWhitelist = expanded;
+    self.expandedWhitelists = _expandedWhitelists;
 }
 
 - (BOOL)schemeIsAllowed:(NSString*)scheme
 {
-    return [scheme isEqualToString:@"http"] ||
-           [scheme isEqualToString:@"https"] ||
-           [scheme isEqualToString:@"ftp"] ||
-           [scheme isEqualToString:@"ftps"];
+    if ([scheme isEqualToString:@"http"] ||
+        [scheme isEqualToString:@"https"] ||
+        [scheme isEqualToString:@"ftp"] ||
+        [scheme isEqualToString:@"ftps"]) {
+        return YES;
+    }
+
+    return (self.expandedWhitelists != nil) && ([self.expandedWhitelists objectForKey:scheme] != nil);
 }
 
 - (BOOL)URLIsAllowed:(NSURL*)url
 {
-    if (self.expandedWhitelist == nil) {
+    NSString* scheme = [url scheme];
+
+    // http[s] and ftp[s] should also validate against the common set in the kCDVDefaultSchemeName list
+    if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"] || [scheme isEqualToString:@"ftp"] || [scheme isEqualToString:@"ftps"]) {
+        NSURL* newUrl = [NSURL URLWithString:[NSString stringWithFormat:@"%@://%@", kCDVDefaultSchemeName, [url host]]];
+        // If it is allowed, we are done.  If not, continue to check for the actual scheme-specific list
+        if ([self URLIsAllowed:newUrl]) {
+            return YES;
+        }
+    }
+
+    // Check that the scheme is supported
+    if (![self schemeIsAllowed:scheme]) {
         return NO;
     }
 
-    if (self.allowAll) {
+    NSArray* expandedWhitelist = [self.expandedWhitelists objectForKey:scheme];
+
+    // Are we allowing everything for this scheme?
+    // TODO: consider just having a static sentinel value for the "allow all" list, so we can use object equality
+    if (([expandedWhitelist count] == 1) && [[expandedWhitelist objectAtIndex:0] isEqualToString:@"*"]) {
         return YES;
     }
 
     // iterate through settings ExternalHosts, check for equality
-    NSEnumerator* enumerator = [self.expandedWhitelist objectEnumerator];
+    NSEnumerator* enumerator = [expandedWhitelist objectEnumerator];
     id regex = nil;
     NSString* urlHost = [url host];
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj b/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
index e14f1f6..c637d60 100644
--- a/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
+++ b/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
@@ -47,6 +47,8 @@
 		68B7516E16FD18190076A8B4 /* CDVJpegHeaderWriter.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B7516B16FD18190076A8B4 /* CDVJpegHeaderWriter.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		68B7516F16FD18190076A8B4 /* CDVJpegHeaderWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 68B7516C16FD18190076A8B4 /* CDVJpegHeaderWriter.m */; };
 		68B7517016FD19F80076A8B4 /* CDVExif.h in Headers */ = {isa = PBXBuildFile; fileRef = 68B7516A16FD18190076A8B4 /* CDVExif.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7E14B5A81705050A0032169E /* CDVTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E14B5A61705050A0032169E /* CDVTimer.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		7E14B5A91705050A0032169E /* CDVTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E14B5A71705050A0032169E /* CDVTimer.m */; };
 		8852C43A14B65FD800F0E735 /* CDVViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 8852C43614B65FD800F0E735 /* CDVViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		8852C43C14B65FD800F0E735 /* CDVViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8852C43714B65FD800F0E735 /* CDVViewController.m */; };
 		8887FD661090FBE7009987E8 /* CDVCamera.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD261090FBE7009987E8 /* CDVCamera.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -55,8 +57,6 @@
 		8887FD691090FBE7009987E8 /* NSDictionary+Extensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 8887FD291090FBE7009987E8 /* NSDictionary+Extensions.m */; };
 		8887FD6A1090FBE7009987E8 /* CDVContacts.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD2A1090FBE7009987E8 /* CDVContacts.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		8887FD6B1090FBE7009987E8 /* CDVContacts.m in Sources */ = {isa = PBXBuildFile; fileRef = 8887FD2B1090FBE7009987E8 /* CDVContacts.m */; };
-		8887FD6C1090FBE7009987E8 /* CDVDebugConsole.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD2C1090FBE7009987E8 /* CDVDebugConsole.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		8887FD6D1090FBE7009987E8 /* CDVDebugConsole.m in Sources */ = {isa = PBXBuildFile; fileRef = 8887FD2D1090FBE7009987E8 /* CDVDebugConsole.m */; };
 		8887FD701090FBE7009987E8 /* CDVFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD301090FBE7009987E8 /* CDVFile.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		8887FD711090FBE7009987E8 /* CDVFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 8887FD311090FBE7009987E8 /* CDVFile.m */; };
 		8887FD741090FBE7009987E8 /* CDVInvokedUrlCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 8887FD341090FBE7009987E8 /* CDVInvokedUrlCommand.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -147,6 +147,8 @@
 		68B7516A16FD18190076A8B4 /* CDVExif.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVExif.h; path = Classes/CDVExif.h; sourceTree = "<group>"; };
 		68B7516B16FD18190076A8B4 /* CDVJpegHeaderWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVJpegHeaderWriter.h; path = Classes/CDVJpegHeaderWriter.h; sourceTree = "<group>"; };
 		68B7516C16FD18190076A8B4 /* CDVJpegHeaderWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVJpegHeaderWriter.m; path = Classes/CDVJpegHeaderWriter.m; sourceTree = "<group>"; };
+		7E14B5A61705050A0032169E /* CDVTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVTimer.h; path = Classes/CDVTimer.h; sourceTree = "<group>"; };
+		7E14B5A71705050A0032169E /* CDVTimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVTimer.m; path = Classes/CDVTimer.m; sourceTree = "<group>"; };
 		8220B5C316D5427E00EC3921 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; };
 		8852C43614B65FD800F0E735 /* CDVViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVViewController.h; path = Classes/CDVViewController.h; sourceTree = "<group>"; };
 		8852C43714B65FD800F0E735 /* CDVViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVViewController.m; path = Classes/CDVViewController.m; sourceTree = "<group>"; };
@@ -156,8 +158,6 @@
 		8887FD291090FBE7009987E8 /* NSDictionary+Extensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSDictionary+Extensions.m"; path = "Classes/NSDictionary+Extensions.m"; sourceTree = "<group>"; };
 		8887FD2A1090FBE7009987E8 /* CDVContacts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVContacts.h; path = Classes/CDVContacts.h; sourceTree = "<group>"; };
 		8887FD2B1090FBE7009987E8 /* CDVContacts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVContacts.m; path = Classes/CDVContacts.m; sourceTree = "<group>"; };
-		8887FD2C1090FBE7009987E8 /* CDVDebugConsole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVDebugConsole.h; path = Classes/CDVDebugConsole.h; sourceTree = "<group>"; };
-		8887FD2D1090FBE7009987E8 /* CDVDebugConsole.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVDebugConsole.m; path = Classes/CDVDebugConsole.m; sourceTree = "<group>"; };
 		8887FD301090FBE7009987E8 /* CDVFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVFile.h; path = Classes/CDVFile.h; sourceTree = "<group>"; };
 		8887FD311090FBE7009987E8 /* CDVFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVFile.m; path = Classes/CDVFile.m; sourceTree = "<group>"; };
 		8887FD341090FBE7009987E8 /* CDVInvokedUrlCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVInvokedUrlCommand.h; path = Classes/CDVInvokedUrlCommand.h; sourceTree = "<group>"; };
@@ -307,8 +307,6 @@
 				1F3C04CD12BC247D004F9E10 /* CDVContact.m */,
 				8887FD2A1090FBE7009987E8 /* CDVContacts.h */,
 				8887FD2B1090FBE7009987E8 /* CDVContacts.m */,
-				8887FD2C1090FBE7009987E8 /* CDVDebugConsole.h */,
-				8887FD2D1090FBE7009987E8 /* CDVDebugConsole.m */,
 				EB80C2AA15DEA63D004D9E7B /* CDVEcho.h */,
 				EB80C2AB15DEA63D004D9E7B /* CDVEcho.m */,
 				8887FD301090FBE7009987E8 /* CDVFile.h */,
@@ -354,6 +352,8 @@
 				30E563CE13E217EC00C949AA /* NSMutableArray+QueueAdditions.m */,
 				8887FD501090FBE7009987E8 /* NSData+Base64.h */,
 				8887FD511090FBE7009987E8 /* NSData+Base64.m */,
+				7E14B5A61705050A0032169E /* CDVTimer.h */,
+				7E14B5A71705050A0032169E /* CDVTimer.m */,
 			);
 			name = Util;
 			sourceTree = "<group>";
@@ -380,7 +380,6 @@
 				8887FD661090FBE7009987E8 /* CDVCamera.h in Headers */,
 				8887FD681090FBE7009987E8 /* NSDictionary+Extensions.h in Headers */,
 				8887FD6A1090FBE7009987E8 /* CDVContacts.h in Headers */,
-				8887FD6C1090FBE7009987E8 /* CDVDebugConsole.h in Headers */,
 				8887FD701090FBE7009987E8 /* CDVFile.h in Headers */,
 				8887FD741090FBE7009987E8 /* CDVInvokedUrlCommand.h in Headers */,
 				8887FD851090FBE7009987E8 /* CDVLocation.h in Headers */,
@@ -420,6 +419,7 @@
 				30F3930B169F839700B22307 /* CDVJSON.h in Headers */,
 				EBFF4DBD16D3FE2E008F452B /* CDVWebViewDelegate.h in Headers */,
 				EB96673B16A8970A00D86CDF /* CDVUserAgentUtil.h in Headers */,
+				7E14B5A81705050A0032169E /* CDVTimer.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -480,7 +480,6 @@
 				8887FD671090FBE7009987E8 /* CDVCamera.m in Sources */,
 				8887FD691090FBE7009987E8 /* NSDictionary+Extensions.m in Sources */,
 				8887FD6B1090FBE7009987E8 /* CDVContacts.m in Sources */,
-				8887FD6D1090FBE7009987E8 /* CDVDebugConsole.m in Sources */,
 				8887FD711090FBE7009987E8 /* CDVFile.m in Sources */,
 				8887FD751090FBE7009987E8 /* CDVInvokedUrlCommand.m in Sources */,
 				8887FD861090FBE7009987E8 /* CDVLocation.m in Sources */,
@@ -516,6 +515,7 @@
 				EB96673C16A8970A00D86CDF /* CDVUserAgentUtil.m in Sources */,
 				EBFF4DBC16D3FE2E008F452B /* CDVWebViewDelegate.m in Sources */,
 				68B7516F16FD18190076A8B4 /* CDVJpegHeaderWriter.m in Sources */,
+				7E14B5A91705050A0032169E /* CDVTimer.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/VERSION b/lib/cordova-ios/CordovaLib/VERSION
index e70b452..59b7056 100644
--- a/lib/cordova-ios/CordovaLib/VERSION
+++ b/lib/cordova-ios/CordovaLib/VERSION
@@ -1 +1 @@
-2.6.0
+2.7.0rc1

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLib/cordova.ios.js
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/cordova.ios.js b/lib/cordova-ios/CordovaLib/cordova.ios.js
index 4df7891..844816f 100644
--- a/lib/cordova-ios/CordovaLib/cordova.ios.js
+++ b/lib/cordova-ios/CordovaLib/cordova.ios.js
@@ -1,8 +1,8 @@
 // Platform: ios
 
-// commit 125dca530923a44a8f44f68f5e1970cbdd4e7faf
+// commit 360bd3e65c33ce4f01e2efb82d641a565ef3c333
 
-// File generated at :: Thu Apr 04 2013 10:21:55 GMT-0700 (PDT)
+// File generated at :: Fri Apr 19 2013 18:36:09 GMT-0700 (PDT)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -219,6 +219,10 @@ var cordova = {
             }
             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);
             }
@@ -742,6 +746,7 @@ channel.createSticky('onDestroy');
 // Channels that must fire before "deviceready" is fired.
 channel.waitForInitialization('onCordovaReady');
 channel.waitForInitialization('onCordovaConnectionReady');
+channel.waitForInitialization('onDOMContentLoaded');
 
 module.exports = channel;
 
@@ -2372,7 +2377,7 @@ function initRead(reader, file) {
 
     if (typeof file == 'string') {
         // Deprecated in Cordova 2.4.
-        console.warning('Using a string argument with FileReader.readAs functions is deprecated.');
+        console.warn('Using a string argument with FileReader.readAs functions is deprecated.');
         reader._fileName = file;
     } else if (typeof file.fullPath == 'string') {
         reader._fileName = file.fullPath;
@@ -2730,7 +2735,7 @@ function getBasicAuthHeader(urlString) {
         var origin = protocol + url.host;
 
         // check whether there are the username:password credentials in the url
-        if (url.href.indexOf(origin) != 0) { // credentials found
+        if (url.href.indexOf(origin) !== 0) { // credentials found
             var atIndex = url.href.indexOf("@");
             credentials = url.href.substring(protocol.length, atIndex);
         }
@@ -2779,15 +2784,11 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
     var params = null;
     var chunkedMode = true;
     var headers = null;
-
+    var httpMethod = null;
     var basicAuthHeader = getBasicAuthHeader(server);
     if (basicAuthHeader) {
-        if (!options) {
-            options = new FileUploadOptions();
-        }
-        if (!options.headers) {
-            options.headers = {};
-        }
+        options = options || {};
+        options.headers = options.headers || {};
         options.headers[basicAuthHeader.name] = basicAuthHeader.value;
     }
 
@@ -2796,6 +2797,12 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
         fileName = options.fileName;
         mimeType = options.mimeType;
         headers = options.headers;
+        httpMethod = options.httpMethod || "POST";
+        if (httpMethod.toUpperCase() == "PUT"){
+            httpMethod = "PUT";
+        } else {
+            httpMethod = "POST";
+        }
         if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") {
             chunkedMode = options.chunkedMode;
         }
@@ -2822,7 +2829,7 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
             successCallback && successCallback(result);
         }
     };
-    exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id]);
+    exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]);
 };
 
 /**
@@ -2840,12 +2847,8 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
 
     var basicAuthHeader = getBasicAuthHeader(source);
     if (basicAuthHeader) {
-        if (!options) {
-            options = {};
-        }
-        if (!options.headers) {
-            options.headers = {};
-        }
+        options = options || {};
+        options.headers = options.headers || {};
         options.headers[basicAuthHeader.name] = basicAuthHeader.value;
     }
 
@@ -2884,12 +2887,11 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
 };
 
 /**
- * Aborts the ongoing file transfer on this object
- * @param successCallback {Function}  Callback to be invoked upon success
- * @param errorCallback {Function}    Callback to be invoked upon error
+ * Aborts the ongoing file transfer on this object. The original error
+ * callback for the file transfer will be called if necessary.
  */
-FileTransfer.prototype.abort = function(successCallback, errorCallback) {
-    exec(successCallback, errorCallback, 'FileTransfer', 'abort', [this._id]);
+FileTransfer.prototype.abort = function() {
+    exec(null, null, 'FileTransfer', 'abort', [this._id]);
 };
 
 module.exports = FileTransfer;
@@ -2933,12 +2935,13 @@ define("cordova/plugin/FileUploadOptions", function(require, exports, module) {
  * @param headers {Object}   Keys are header names, values are header values. Multiple
  *                           headers of the same name are not supported.
  */
-var FileUploadOptions = function(fileKey, fileName, mimeType, params, headers) {
+var FileUploadOptions = function(fileKey, fileName, mimeType, params, headers, httpMethod) {
     this.fileKey = fileKey || null;
     this.fileName = fileName || null;
     this.mimeType = mimeType || null;
     this.params = params || null;
     this.headers = headers || null;
+    this.httpMethod = httpMethod || null;
 };
 
 module.exports = FileUploadOptions;
@@ -3273,6 +3276,7 @@ define("cordova/plugin/InAppBrowser", function(require, exports, module) {
 
 var exec = require('cordova/exec');
 var channel = require('cordova/channel');
+var modulemapper = require('cordova/modulemapper');
 
 function InAppBrowser() {
    this.channels = {
@@ -3301,6 +3305,26 @@ InAppBrowser.prototype = {
         if (eventname in this.channels) {
             this.channels[eventname].unsubscribe(f);
         }
+    },
+
+    executeScript: function(injectDetails, cb) {
+        if (injectDetails.code) {
+            exec(cb, null, "InAppBrowser", "injectScriptCode", [injectDetails.code, !!cb]);
+        } else if (injectDetails.file) {
+            exec(cb, null, "InAppBrowser", "injectScriptFile", [injectDetails.file, !!cb]);
+        } else {
+            throw new Error('executeScript requires exactly one of code or file to be specified');
+        }
+    },
+
+    insertCSS: function(injectDetails, cb) {
+        if (injectDetails.code) {
+            exec(cb, null, "InAppBrowser", "injectStyleCode", [injectDetails.code, !!cb]);
+        } else if (injectDetails.file) {
+            exec(cb, null, "InAppBrowser", "injectStyleFile", [injectDetails.file, !!cb]);
+        } else {
+            throw new Error('insertCSS requires exactly one of code or file to be specified');
+        }
     }
 };
 
@@ -3309,6 +3333,13 @@ module.exports = function(strUrl, strWindowName, strWindowFeatures) {
     var cb = function(eventname) {
        iab._eventHandler(eventname);
     };
+
+    // Don't catch calls that write to existing frames (e.g. named iframes).
+    if (window.frames && window.frames[strWindowName]) {
+        var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open');
+        return origOpenFunc.apply(window, arguments);
+    }
+
     exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
     return iab;
 };
@@ -4275,7 +4306,7 @@ console.debug = function() {
 console.assert = function(expression) {
     if (expression) return;
 
-    var message = utils.vformat(arguments[1], [].slice.call(arguments, 2));
+    var message = logger.format.apply(logger.format, [].slice.call(arguments, 1));
     console.log("ASSERT: " + message);
 };
 
@@ -5257,93 +5288,6 @@ module.exports = {
 
 });
 
-// file: lib/ios/plugin/ios/console.js
-define("cordova/plugin/ios/console", function(require, exports, module) {
-
-var exec = require('cordova/exec');
-
-/**
- * create a nice string for an object
- */
-function stringify(message) {
-    try {
-        if (typeof message === "object" && JSON && JSON.stringify) {
-            try {
-                return JSON.stringify(message);
-            }
-            catch (e) {
-                return "error JSON.stringify()ing argument: " + e;
-            }
-        } else {
-            return (typeof message === "undefined") ? "undefined" : message.toString();
-        }
-    } catch (e) {
-        return e.toString();
-    }
-}
-
-/**
- * Wrapper one of the console logging methods, so that
- * the Cordova logging native is called, then the original.
- */
-function wrappedMethod(console, method) {
-    var origMethod = console[method];
-
-    return function() {
-
-        var args = [].slice.call(arguments),
-            len = args.length,
-            i = 0,
-            res = [];
-
-        for ( ; i < len; i++) {
-            res.push(stringify(args[i]));
-        }
-
-        exec(null, null,
-            'Debug Console', 'log',
-            [ res.join(' '), { logLevel: method.toUpperCase() } ]
-        );
-
-        if (!origMethod) return;
-
-        origMethod.apply(console, arguments);
-    };
-}
-
-var console = window.console || {};
-
-// 2012-10-06 pmuellr - marking setLevel() method and logLevel property
-// on console as deprecated;
-// it didn't do anything useful, since the level constants weren't accessible
-// to anyone
-
-console.setLevel = function() {};
-console.logLevel = 0;
-
-// wrapper the logging messages
-
-var methods = ["log", "debug", "info", "warn", "error"];
-
-for (var i=0; i<methods.length; i++) {
-    var method = methods[i];
-
-    console[method] = wrappedMethod(console, method);
-}
-
-module.exports = console;
-
-});
-
-// file: lib/ios/plugin/ios/console/symbols.js
-define("cordova/plugin/ios/console/symbols", function(require, exports, module) {
-
-var modulemapper = require('cordova/modulemapper');
-
-modulemapper.clobbers('cordova/plugin/ios/console', 'console');
-
-});
-
 // file: lib/ios/plugin/ios/contacts.js
 define("cordova/plugin/ios/contacts", function(require, exports, module) {
 
@@ -5421,6 +5365,16 @@ logger.useConsole(false);
 
 });
 
+// file: lib/ios/plugin/ios/logger/symbols.js
+define("cordova/plugin/ios/logger/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/logger', 'console');
+
+});
+
 // file: lib/ios/plugin/ios/notification.js
 define("cordova/plugin/ios/notification", function(require, exports, module) {
 
@@ -5605,10 +5559,10 @@ function logWithArgs(level, args) {
  * Parameters passed after message are used applied to
  * the message with utils.format()
  */
-logger.logLevel = function(level, message /* , ... */) {
+logger.logLevel = function(level /* , ... */) {
     // format the message with the parameters
-    var formatArgs = [].slice.call(arguments, 2);
-    message    = utils.vformat(message, formatArgs);
+    var formatArgs = [].slice.call(arguments, 1);
+    var message    = logger.format.apply(logger.format, formatArgs);
 
     if (LevelsMap[level] === null) {
         throw new Error("invalid logging level: " + level);
@@ -5643,6 +5597,92 @@ logger.logLevel = function(level, message /* , ... */) {
     }
 };
 
+
+/**
+ * Formats a string and arguments following it ala console.log()
+ *
+ * Any remaining arguments will be appended to the formatted string.
+ *
+ * for rationale, see FireBug's Console API:
+ *    http://getfirebug.com/wiki/index.php/Console_API
+ */
+logger.format = function(formatString, args) {
+    return __format(arguments[0], [].slice.call(arguments,1)).join(' ');
+};
+
+
+//------------------------------------------------------------------------------
+/**
+ * Formats a string and arguments following it ala vsprintf()
+ *
+ * format chars:
+ *   %j - format arg as JSON
+ *   %o - format arg as JSON
+ *   %c - format arg as ''
+ *   %% - replace with '%'
+ * any other char following % will format it's
+ * arg via toString().
+ *
+ * Returns an array containing the formatted string and any remaining
+ * arguments.
+ */
+function __format(formatString, args) {
+    if (formatString === null || formatString === undefined) return [""];
+    if (arguments.length == 1) return [formatString.toString()];
+
+    if (typeof formatString != "string")
+        formatString = formatString.toString();
+
+    var pattern = /(.*?)%(.)(.*)/;
+    var rest    = formatString;
+    var result  = [];
+
+    while (args.length) {
+        var match = pattern.exec(rest);
+        if (!match) break;
+
+        var arg   = args.shift();
+        rest = match[3];
+        result.push(match[1]);
+
+        if (match[2] == '%') {
+            result.push('%');
+            args.unshift(arg);
+            continue;
+        }
+
+        result.push(__formatted(arg, match[2]));
+    }
+
+    result.push(rest);
+
+    var remainingArgs = [].slice.call(args);
+    remainingArgs.unshift(result.join(''));
+    return remainingArgs;
+}
+
+function __formatted(object, formatChar) {
+
+    try {
+        switch(formatChar) {
+            case 'j':
+            case 'o': return JSON.stringify(object);
+            case 'c': return '';
+        }
+    }
+    catch (e) {
+        return "error JSON.stringify()ing argument: " + e;
+    }
+
+    if ((object === null) || (object === undefined)) {
+        return Object.prototype.toString.call(object);
+    }
+
+    return object.toString();
+}
+
+
+//------------------------------------------------------------------------------
 // when deviceready fires, log queued messages
 logger.__onDeviceReady = function() {
     if (DeviceReady) return;
@@ -5811,13 +5851,13 @@ module.exports = {
             console.log("Notification.confirm(string, function, string, string) is deprecated.  Use Notification.confirm(string, function, string, array).");
         }
 
-        // Android and iOS take an array of button label names.
+        // Some platforms take an array of button label names.
         // Other platforms take a comma separated list.
         // For compatibility, we convert to the desired type based on the platform.
-        if (platform.id == "android" || platform.id == "ios") {
+        if (platform.id == "android" || platform.id == "ios" || platform.id == "windowsphone") {
             if (typeof _buttonLabels === 'string') {
                 var buttonLabelString = _buttonLabels;
-                _buttonLabels = buttonLabelString.split(",");
+                _buttonLabels = _buttonLabels.split(","); // not crazy about changing the var type here
             }
         } else {
             if (Array.isArray(_buttonLabels)) {
@@ -6168,62 +6208,6 @@ utils.alert = function(msg) {
     }
 };
 
-/**
- * Formats a string and arguments following it ala sprintf()
- *
- * see utils.vformat() for more information
- */
-utils.format = function(formatString /* ,... */) {
-    var args = [].slice.call(arguments, 1);
-    return utils.vformat(formatString, args);
-};
-
-/**
- * Formats a string and arguments following it ala vsprintf()
- *
- * format chars:
- *   %j - format arg as JSON
- *   %o - format arg as JSON
- *   %c - format arg as ''
- *   %% - replace with '%'
- * any other char following % will format it's
- * arg via toString().
- *
- * for rationale, see FireBug's Console API:
- *    http://getfirebug.com/wiki/index.php/Console_API
- */
-utils.vformat = function(formatString, args) {
-    if (formatString === null || formatString === undefined) return "";
-    if (arguments.length == 1) return formatString.toString();
-    if (typeof formatString != "string") return formatString.toString();
-
-    var pattern = /(.*?)%(.)(.*)/;
-    var rest    = formatString;
-    var result  = [];
-
-    while (args.length) {
-        var arg   = args.shift();
-        var match = pattern.exec(rest);
-
-        if (!match) break;
-
-        rest = match[3];
-
-        result.push(match[1]);
-
-        if (match[2] == '%') {
-            result.push('%');
-            args.unshift(arg);
-            continue;
-        }
-
-        result.push(formatted(arg, match[2]));
-    }
-
-    result.push(rest);
-
-    return result.join('');
-};
 
 //------------------------------------------------------------------------------
 function UUIDcreatePart(length) {
@@ -6238,26 +6222,6 @@ function UUIDcreatePart(length) {
     return uuidpart;
 }
 
-//------------------------------------------------------------------------------
-function formatted(object, formatChar) {
-
-    try {
-        switch(formatChar) {
-            case 'j':
-            case 'o': return JSON.stringify(object);
-            case 'c': return '';
-        }
-    }
-    catch (e) {
-        return "error JSON.stringify()ing argument: " + e;
-    }
-
-    if ((object === null) || (object === undefined)) {
-        return Object.prototype.toString.call(object);
-    }
-
-    return object.toString();
-}
 
 });
 
@@ -6267,6 +6231,25 @@ window.cordova = require('cordova');
 // file: lib/scripts/bootstrap.js
 
 (function (context) {
+    var channel = require('cordova/channel');
+    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) {
@@ -6288,8 +6271,6 @@ window.cordova = require('cordova');
         context.navigator = replaceNavigator(context.navigator);
     }
 
-    var channel = require("cordova/channel");
-
     // _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.
@@ -6298,32 +6279,33 @@ window.cordova = require('cordova');
     }
 
     /**
-     * Create all cordova objects once page has fully loaded and native side is ready.
+     * Create all cordova objects once native side is ready.
      */
     channel.join(function() {
-        var builder = require('cordova/builder'),
-            platform = require('cordova/platform');
-
-        builder.buildIntoButDoNotClobber(platform.defaults, context);
-        builder.buildIntoAndClobber(platform.clobbers, context);
-        builder.buildIntoAndMerge(platform.merges, context);
-
         // Call the platform-specific initialization
-        platform.initialize();
+        require('cordova/platform').initialize();
 
         // Fire event to notify that all objects are created
         channel.onCordovaReady.fire();
 
-        // Fire onDeviceReady event once all constructors have run and
-        // cordova info has been received from native side.
+        // Fire onDeviceReady event once page has fully loaded, all
+        // constructors have run and cordova info has been received from native
+        // side.
+        // This join call is deliberately made after platform.initialize() in
+        // order that plugins may manipulate channel.deviceReadyChannelsArray
+        // if necessary.
         channel.join(function() {
             require('cordova').fireDocumentEvent('deviceready');
         }, channel.deviceReadyChannelsArray);
 
-    }, [ channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady ]);
+    }, platformInitChannelsArray);
 
 }(window));
 
+// file: lib/scripts/bootstrap-ios.js
+
+require('cordova/channel').onNativeReady.fire();
+
 // file: lib/scripts/plugin_loader.js
 
 // Tries to load all plugins' js-modules.
@@ -6399,31 +6381,27 @@ window.cordova = require('cordova');
         }
     }
 
+
     // Try to XHR the cordova_plugins.json file asynchronously.
-    try { // we commented we were going to try, so let us actually try and catch 
+    try { // we commented we were going to try, so let us actually try and catch
         var xhr = new context.XMLHttpRequest();
-        xhr.onreadystatechange = function() {
-            if (this.readyState != 4) { // not DONE
-                return;
-            }
-
+        xhr.onload = function() {
             // If the response is a JSON string which composes an array, call handlePluginsObject.
             // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
-            if (this.status == 200) {
-                var obj = JSON.parse(this.responseText);
-                if (obj && obj instanceof Array && obj.length > 0) {
-                    handlePluginsObject(obj);
-                } else {
-                    finishPluginLoading();
-                }
+            var obj = JSON.parse(this.responseText);
+            if (obj && obj instanceof Array && obj.length > 0) {
+                handlePluginsObject(obj);
             } else {
                 finishPluginLoading();
             }
         };
+        xhr.onerror = function() {
+            finishPluginLoading();
+        };
         xhr.open('GET', 'cordova_plugins.json', true); // Async
         xhr.send();
     }
-    catch(err) {
+    catch(err){
         finishPluginLoading();
     }
 }(window));

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLibTests/CDVWhitelistTests.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/CDVWhitelistTests.m b/lib/cordova-ios/CordovaLibTests/CDVWhitelistTests.m
index 172b62e..21576a3 100644
--- a/lib/cordova-ios/CordovaLibTests/CDVWhitelistTests.m
+++ b/lib/cordova-ios/CordovaLibTests/CDVWhitelistTests.m
@@ -149,9 +149,10 @@
     CDVWhitelist* whitelist = [[CDVWhitelist alloc] initWithArray:allowedHosts];
 
     STAssertTrue([whitelist URLIsAllowed:[NSURL URLWithString:@"http://apache.org"]], nil);
-    STAssertTrue([whitelist URLIsAllowed:[NSURL URLWithString:@"http://build.apache.prg"]], nil);
-    STAssertTrue([whitelist URLIsAllowed:[NSURL URLWithString:@"http://MyDangerousSite.org"]], nil);
-    STAssertTrue([whitelist URLIsAllowed:[NSURL URLWithString:@"http://apache.org.SuspiciousSite.com"]], nil);
+    STAssertTrue([whitelist URLIsAllowed:[NSURL URLWithString:@"https://build.apache.prg"]], nil);
+    STAssertTrue([whitelist URLIsAllowed:[NSURL URLWithString:@"ftp://MyDangerousSite.org"]], nil);
+    STAssertTrue([whitelist URLIsAllowed:[NSURL URLWithString:@"ftps://apache.org.SuspiciousSite.com"]], nil);
+    STAssertFalse([whitelist URLIsAllowed:[NSURL URLWithString:@"gopher://apache.org"]], nil);
 }
 
 - (void)testWildcardInHostname
@@ -274,4 +275,19 @@
     STAssertTrue([expectedErrorString isEqualToString:errorString], @"Customized whitelist rejection string has unexpected value.");
 }
 
+- (void)testSpecificProtocol
+{
+    NSArray* allowedHosts = [NSArray arrayWithObjects:
+        @"http://www.apache.org",
+        @"cordova://www.google.com",
+        nil];
+
+    CDVWhitelist* whitelist = [[CDVWhitelist alloc] initWithArray:allowedHosts];
+
+    STAssertTrue([whitelist URLIsAllowed:[NSURL URLWithString:@"http://www.apache.org"]], nil);
+    STAssertTrue([whitelist URLIsAllowed:[NSURL URLWithString:@"cordova://www.google.com"]], nil);
+    STAssertFalse([whitelist URLIsAllowed:[NSURL URLWithString:@"cordova://www.apache.org"]], nil);
+    STAssertFalse([whitelist URLIsAllowed:[NSURL URLWithString:@"http://www.google.com"]], nil);
+}
+
 @end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml b/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml
index 5610e5e..f8a2fad 100644
--- a/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml
+++ b/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml
@@ -25,7 +25,6 @@
         <plugin name="Camera" value="CDVCamera" />
         <plugin name="NetworkStatus" value="CDVConnection" />
         <plugin name="Contacts" value="CDVContacts" />
-        <plugin name="Debug Console" value="CDVDebugConsole" />
         <plugin name="File" value="CDVFile" />
         <plugin name="FileTransfer" value="CDVFileTransfer" />
         <plugin name="Geolocation" value="CDVLocation" />

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/RELEASENOTES.md
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/RELEASENOTES.md b/lib/cordova-ios/RELEASENOTES.md
index aa501b0..ffe0c0b 100644
--- a/lib/cordova-ios/RELEASENOTES.md
+++ b/lib/cordova-ios/RELEASENOTES.md
@@ -22,6 +22,45 @@
  
  Cordova is a static library that enables developers to include the Cordova API in their iOS application projects easily, and also create new Cordova-based iOS application projects through the command-line.
 
+### 2.7.0 (201304XX) ###
+
+* Fix NPE in InAppBrowser's error callback.
+* [CB-2849] Fix bin/create when CordovaLib parent dir has a space
+* [CB-3069] Fix InAppBrowser load events (for non-redirecting pages)
+* InAppBrowser: Don't inject iframe bridge until necessary.
+* Fix FileTransfer unit test. HTTP Method was being set to null.
+* [CB-2305] Add InAppBrowser injectSriptCode command to support InAppBrowser.executeScript and InAppBrowser.insertCSS APIs
+* [CB-2653] Simplify InAppBrowser.injectScriptCode.
+* [CB-2537] Implement streaming downloads for FileTransfer
+* [CB-2190] Allow FileTransfer uploads to continue in background
+* [CB-1518] Request content length in parallel with download for gzipped content
+* [CB-2653] Delay executeScript/insertCSS callback until resources have loaded; pass JS results to callback
+* [CB-2824] Remove DebugConsole plugin
+* [CB-3066] Fire onNativeReady from JS, as bridge is available immediately
+* [CB-2725] Fix www deploy issues with symlinks
+* [CB-2725] follow links in www copy script
+* [CB-3039] iOS Exif date length mismtach
+* [CB-3052] iOS Exif SubIFD offsets incorrect
+* [CB-51] Added httpMethod for file transfer options (defaults to POST)
+* [CB-2732] Only set camera device when allowed.
+* [CB-2911] Updated resolveLocalFileSystemURI.
+* [CB-3032] Add whitelist support for custom schemes.
+* [CB-3048] Add --arc flag to create script, support arc in template.
+* [CB-3067]: fixing ios5 whitelist of file url
+* [CB-3067] Revert CDVURLProtocol to not whitelist file urls
+* [CB-2788] add ./bin/check_reqs script to iOS
+* [CB-2587] Added plugin timing for plugins that are loaded on startup (plugin 'onload' attribute)
+* [CB-2848] ShowSplashScreenSpinner not used
+* [CB-2960] Changing the volume of a sound already playing
+* [CB-3021] Can no longer import CDVPlugin.h from plugin Objective-C++ code
+* [CB-2790] added splice function to header writer: accepts jpeg as NSData, and splices in exif data specified by a string
+* [CB-2790] removed old splice code, replaced with JpegHeaderWriter api calls
+* [CB-2896] split writing of working tags off here, multipart tags not supported
+* [CB-2896] fixed error in exif subifd offset calculation for tag 8769
+* [CB-2902] re-added long/short tags to template dict, fixed subExifIFD offset
+
+<br />
+
 ### 2.6.0 (20130401) ###
 
 * [CB-2732] Only set camera device when allowed.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/bin/check_reqs
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/check_reqs b/lib/cordova-ios/bin/check_reqs
new file mode 100755
index 0000000..27d00c3
--- /dev/null
+++ b/lib/cordova-ios/bin/check_reqs
@@ -0,0 +1,34 @@
+#! /bin/sh
+
+#
+# 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.
+#
+
+XCODEBUILD_LOCATION=$(which xcodebuild)
+if [ $? != 0 ]; then
+	echo "Xcode is (probably) not installed, specifically the command 'xcodebuild' is unavailable."
+	exit 1
+fi
+
+XCODEBUILD_MIN_VERSION="4.5"
+XCODEBUILD_VERSION=$(xcodebuild -version | head -n 1 | sed -e 's/Xcode //')
+
+if [[ "$XCODEBUILD_VERSION" < "$XCODEBUILD_MIN_VERSION" ]]; then
+	echo "Cordova can only run in Xcode version $XCODEBUILD_MIN_VERSION or greater."
+	exit 1
+fi

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/bin/templates/project/__TESTING__.xcodeproj/project.pbxproj
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__.xcodeproj/project.pbxproj b/lib/cordova-ios/bin/templates/project/__TESTING__.xcodeproj/project.pbxproj
index f5ed342..0af952e 100755
--- a/lib/cordova-ios/bin/templates/project/__TESTING__.xcodeproj/project.pbxproj
+++ b/lib/cordova-ios/bin/templates/project/__TESTING__.xcodeproj/project.pbxproj
@@ -404,7 +404,7 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "SRC_DIR=\"www\"\nDST_DIR=\"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/www\"\nCOPY_HIDDEN=\nORIG_IFS=$IFS\nIFS=$(echo -en \"\\n\\b\")\n\nif [[ ! -e \"$SRC_DIR\" ]]; then\n  echo \"Path does not exist: $SRC_DIR\"\n  exit 1\nfi\n\nif [[ -n $COPY_HIDDEN ]]; then\n  alias do_find='find \"$SRC_DIR\"'\nelse\n  alias do_find='find \"$SRC_DIR\" -name \".*\" -prune -o'\nfi\n\ntime (\n# Code signing files must be removed or else there are\n# resource signing errors.\nrm -rf \"$DST_DIR\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/_CodeSignature\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/PkgInfo\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/embedded.mobileprovision\"\n\n# Directories\nfor p in $(do_find -type d -print); do\n  subpath=\"${p#$SRC_DIR}\"\n  mkdir \"$DST_DIR$subpath\" || exit 1\ndone\n\n# Symlinks\nfor p in $(do_find -type l -print); do\n  subpath=\"${p#$SRC_DIR}\"\n  rsync -a \"$SRC_DIR$subpath\" \"$DST_DIR$subpath\" || exit 2\ndone\n\n# Fi
 les\nfor p in $(do_find -type f -print); do\n  subpath=\"${p#$SRC_DIR}\"\n  if ! ln \"$SRC_DIR$subpath\" \"$DST_DIR$subpath\" 2>/dev/null; then\n    rsync -a \"$SRC_DIR$subpath\" \"$DST_DIR$subpath\" || exit 3\n  fi\ndone\n\n)\nIFS=$ORIG_IFS";
+			shellScript = "SRC_DIR=\"www/\"\nDST_DIR=\"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/www\"\nCOPY_HIDDEN=\nORIG_IFS=$IFS\nIFS=$(echo -en \"\\n\\b\")\n\nif [[ ! -e \"$SRC_DIR\" ]]; then\n  echo \"Path does not exist: $SRC_DIR\"\n  exit 1\nfi\n\nif [[ -n $COPY_HIDDEN ]]; then\n  alias do_find='find \"$SRC_DIR\"'\nelse\n  alias do_find='find -L \"$SRC_DIR\" -name \".*\" -prune -o'\nfi\n\ntime (\n# Code signing files must be removed or else there are\n# resource signing errors.\nrm -rf \"$DST_DIR\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/_CodeSignature\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/PkgInfo\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/embedded.mobileprovision\"\n\n# Directories\nfor p in $(do_find -type d -print); do\n  subpath=\"${p#$SRC_DIR}\"\n  mkdir \"$DST_DIR$subpath\" || exit 1\ndone\n\n# Symlinks\nfor p in $(do_find -type l -print); do\n  subpath=\"${p#$SRC_DIR}\"\n  source=$(readlink $SRC_DIR$subpath)\n  sourcetype=$(stat -f \"%HT%SY\"
  $source)\n  if [ \"$sourcetype\" = \"Directory\" ]; then\n    mkdir \"$DST_DIR$subpath\" || exit 2\n  else\n    rsync -a \"$source\" \"$DST_DIR$subpath\" || exit 3\n  fi\ndone\n\n# Files\nfor p in $(do_find -type f -print); do\n  subpath=\"${p#$SRC_DIR}\"\n  if ! ln \"$SRC_DIR$subpath\" \"$DST_DIR$subpath\" 2>/dev/null; then\n    rsync -a \"$SRC_DIR$subpath\" \"$DST_DIR$subpath\" || exit 4\n  fi\ndone\n\n)\nIFS=$ORIG_IFS";
 		};
 /* End PBXShellScriptBuildPhase section */
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m b/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
index 623ad8e..5c05ac8 100644
--- a/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
+++ b/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
@@ -45,7 +45,11 @@
 
     int cacheSizeMemory = 8 * 1024 * 1024; // 8MB
     int cacheSizeDisk = 32 * 1024 * 1024; // 32MB
-    NSURLCache* sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"] autorelease];
+#if __has_feature(objc_arc)
+        NSURLCache* sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"];
+#else
+        NSURLCache* sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"] autorelease];
+#endif
     [NSURLCache setSharedURLCache:sharedCache];
 
     self = [super init];
@@ -61,10 +65,18 @@
 {
     CGRect screenBounds = [[UIScreen mainScreen] bounds];
 
-    self.window = [[[UIWindow alloc] initWithFrame:screenBounds] autorelease];
+#if __has_feature(objc_arc)
+        self.window = [[UIWindow alloc] initWithFrame:screenBounds];
+#else
+        self.window = [[[UIWindow alloc] initWithFrame:screenBounds] autorelease];
+#endif
     self.window.autoresizesSubviews = YES;
 
-    self.viewController = [[[MainViewController alloc] init] autorelease];
+#if __has_feature(objc_arc)
+        self.viewController = [[MainViewController alloc] init];
+#else
+        self.viewController = [[[MainViewController alloc] init] autorelease];
+#endif
     self.viewController.useSplashScreen = YES;
 
     // Set your app's start page by setting the <content src='foo.html' /> tag in config.xml.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml b/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml
index 8889726..537705d 100644
--- a/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml
+++ b/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml
@@ -46,7 +46,6 @@
         <plugin name="Camera" value="CDVCamera" />
         <plugin name="NetworkStatus" value="CDVConnection" />
         <plugin name="Contacts" value="CDVContacts" />
-        <plugin name="Debug Console" value="CDVDebugConsole" />
         <plugin name="Echo" value="CDVEcho" />
         <plugin name="File" value="CDVFile" />
         <plugin name="FileTransfer" value="CDVFileTransfer" />

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index 04c45f6..eede08a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "cordova",
-  "version": "2.6.2",
+  "version": "2.7.0-rc.1",
   "preferGlobal": "true",
   "description": "Cordova command line interface tool",
   "main": "cordova",


[28/43] git commit: [npm] Version 2.6.1

Posted by an...@apache.org.
[npm] Version 2.6.1

The upgrade to Cordova 2.6.0 did not increment the npm version.


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

Branch: refs/heads/master
Commit: f03b1e4f0f18e3bfd32d1a15bdea8a0d037acc5e
Parents: ab58257
Author: Michael Brooks <mi...@michaelbrooks.ca>
Authored: Wed Apr 17 16:37:33 2013 -0600
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu May 9 14:26:06 2013 -0700

----------------------------------------------------------------------
 package.json |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f03b1e4f/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index 207849c..563e222 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "cordova",
-  "version": "2.6.0",
+  "version": "2.6.1",
   "preferGlobal": "true",
   "description": "Cordova command line interface tool",
   "main": "cordova",


[13/43] git commit: [CB-3057] Change iOS platform to default to ARC.

Posted by an...@apache.org.
[CB-3057] Change iOS platform to default to ARC.


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

Branch: refs/heads/master
Commit: 548ae5271a3c651aa342a0f1d8b162d19c34310e
Parents: be6d2ed
Author: Michal Mocny <mm...@gmail.com>
Authored: Wed Apr 17 16:48:19 2013 -0400
Committer: Michal Mocny <mm...@gmail.com>
Committed: Wed Apr 17 16:48:19 2013 -0400

----------------------------------------------------------------------
 lib/cordova-ios/bin/create                         |   13 +++++++-
 .../project/__TESTING__/Classes/AppDelegate.m      |   22 +++++++++++---
 src/platform.js                                    |    3 +-
 3 files changed, 30 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/548ae527/lib/cordova-ios/bin/create
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/create b/lib/cordova-ios/bin/create
index bef0f57..d617f09 100755
--- a/lib/cordova-ios/bin/create
+++ b/lib/cordova-ios/bin/create
@@ -31,8 +31,9 @@
 set -e
 
 function usage() {
-  echo "Usage: $0 [--shared] <path_to_new_project> <package_name> <project_name>"
+  echo "Usage: $0 [--shared] [--arc] <path_to_new_project> <package_name> <project_name>"
   echo "	--shared (optional): Link directly against the shared copy of the CordovaLib instead of a copy of it."
+  echo "	--arc (optional): Enable ARC."
   echo "	<path_to_new_project>: Path to your new Cordova iOS project"
   echo "	<package_name>: Package name, following reverse-domain style convention"
   echo "	<project_name>: Project name"
@@ -40,10 +41,15 @@ function usage() {
 }
 
 USE_SHARED=0
+USE_ARC=0
 if [[ $1 == "--shared" ]]; then
     USE_SHARED=1
     shift;
 fi
+if [[ $1 == "--arc" ]]; then
+    USE_ARC=1
+    shift;
+fi
 
 # check whether it is a proper create command (at least 3 arguments)
 if [ $# -lt 3 ]; then
@@ -59,7 +65,7 @@ done
 
 BINDIR=$( cd "$( dirname "$SCRIPT" )" && pwd )
 CORDOVALIB_DIR="$BINDIR/../CordovaLib"
-CDV_VER=$(cat $CORDOVALIB_DIR/VERSION)
+CDV_VER=$(cat "$CORDOVALIB_DIR/VERSION")
 
 PROJECT_PATH=$1
 PACKAGE=$2
@@ -134,3 +140,6 @@ else
     "$BINDIR/update_cordova_subproject" "$R.xcodeproj/project.pbxproj" "$PROJECT_PATH/CordovaLib/CordovaLib.xcodeproj/project.pbxproj" > /dev/null
 fi
 
+if [[ $USE_ARC = 1 ]]; then
+    /usr/bin/sed -i '' 's/CLANG_ENABLE_OBJC_ARC = NO/CLANG_ENABLE_OBJC_ARC = YES/' "$R.xcodeproj/project.pbxproj" > /dev/null
+fi

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/548ae527/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m b/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
index 318f793..5c05ac8 100644
--- a/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
+++ b/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
@@ -45,7 +45,11 @@
 
     int cacheSizeMemory = 8 * 1024 * 1024; // 8MB
     int cacheSizeDisk = 32 * 1024 * 1024; // 32MB
-    NSURLCache* sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"];
+#if __has_feature(objc_arc)
+        NSURLCache* sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"];
+#else
+        NSURLCache* sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"] autorelease];
+#endif
     [NSURLCache setSharedURLCache:sharedCache];
 
     self = [super init];
@@ -61,10 +65,18 @@
 {
     CGRect screenBounds = [[UIScreen mainScreen] bounds];
 
-    self.window = [[[UIWindow alloc] initWithFrame:screenBounds] autorelease];
+#if __has_feature(objc_arc)
+        self.window = [[UIWindow alloc] initWithFrame:screenBounds];
+#else
+        self.window = [[[UIWindow alloc] initWithFrame:screenBounds] autorelease];
+#endif
     self.window.autoresizesSubviews = YES;
 
-    self.viewController = [[[MainViewController alloc] init] autorelease];
+#if __has_feature(objc_arc)
+        self.viewController = [[MainViewController alloc] init];
+#else
+        self.viewController = [[[MainViewController alloc] init] autorelease];
+#endif
     self.viewController.useSplashScreen = YES;
 
     // Set your app's start page by setting the <content src='foo.html' /> tag in config.xml.
@@ -99,8 +111,8 @@
 }
 
 // repost the localnotification using the default NSNotificationCenter so multiple plugins may respond
-- (void)           application:(UIApplication*)application
-   didReceiveLocalNotification:(UILocalNotification*)notification
+- (void)            application:(UIApplication*)application
+    didReceiveLocalNotification:(UILocalNotification*)notification
 {
     // re-post ( broadcast )
     [[NSNotificationCenter defaultCenter] postNotificationName:CDVLocalNotification object:notification];

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/548ae527/src/platform.js
----------------------------------------------------------------------
diff --git a/src/platform.js b/src/platform.js
index a5db481..1862f72 100644
--- a/src/platform.js
+++ b/src/platform.js
@@ -86,11 +86,12 @@ module.exports = function platform(command, targets, callback) {
                         // TODO: eventually refactor to allow multiple versions to be created.
                         // Run platform's create script
                         var bin = path.join(cordova_util.libDirectory, 'cordova-' + target, 'bin', 'create');
+                        var args = (target=='ios') ? '--arc' : '';
                         var pkg = cfg.packageName().replace(/[^\w.]/g,'_');
                         var name = cfg.name().replace(/\W/g,'_');
                         // TODO: PLATFORM LIBRARY INCONSISTENCY: order/number of arguments to create
                         // TODO: keep tabs on CB-2300
-                        var command = util.format('"%s" "%s" "%s" "%s"', bin, output, (target=='blackberry'?name:pkg), name);
+                        var command = util.format('"%s" %s "%s" "%s" "%s"', bin, args, output, (target=='blackberry'?name:pkg), name);
 
                         shell.exec(command, {silent:true,async:true}, function(code, create_output) {
                             if (code > 0) {


[35/43] Version 2.7.0-rc.1

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators b/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators
new file mode 100755
index 0000000..7911763
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators
@@ -0,0 +1,23 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
+
+bash "$CORDOVA_LIB_PATH"/cordova list-started-emulators
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators.bat b/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators.bat
new file mode 100644
index 0000000..f1b3c5d
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%cordova.js (
+    cscript "%full_path%cordova.js" list-started-emulators //nologo
+) ELSE (
+    ECHO. 
+    ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/lib/start-emulator
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/start-emulator b/lib/cordova-android/bin/templates/cordova/lib/start-emulator
new file mode 100755
index 0000000..8e8964d
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/start-emulator
@@ -0,0 +1,23 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
+
+bash "$CORDOVA_LIB_PATH"/cordova start-emulator "$@"
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/lib/start-emulator.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/start-emulator.bat b/lib/cordova-android/bin/templates/cordova/lib/start-emulator.bat
new file mode 100644
index 0000000..4f3fb5d
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/lib/start-emulator.bat
@@ -0,0 +1,9 @@
+@ECHO OFF
+SET full_path=%~dp0
+IF EXIST %full_path%cordova.js (
+    cscript "%full_path%cordova.js" start-emulator %* //nologo
+) ELSE (
+    ECHO. 
+    ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
+    EXIT /B 1
+)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/log
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/log b/lib/cordova-android/bin/templates/cordova/log
index 087a200..01fe107 100755
--- a/lib/cordova-android/bin/templates/cordova/log
+++ b/lib/cordova-android/bin/templates/cordova/log
@@ -1,3 +1,4 @@
+#!/bin/bash
 # 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
@@ -15,10 +16,8 @@
 # specific language governing permissions and limitations
 # under the License.
 
-#!/bin/bash
-
 set -e
 
 CORDOVA_PATH=$( cd "$( dirname "$0" )/.." && pwd )
 
-bash "$CORDOVA_PATH"/cordova/cordova log
+bash "$CORDOVA_PATH"/cordova/lib/cordova log "$@"

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/log.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/log.bat b/lib/cordova-android/bin/templates/cordova/log.bat
index b8cc6be..2c492e7 100644
--- a/lib/cordova-android/bin/templates/cordova/log.bat
+++ b/lib/cordova-android/bin/templates/cordova/log.bat
@@ -1,18 +1,2 @@
-:: 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.
-
-%~dp0\cordova.bat log
+@ECHO OFF
+%~dp0\cordova.bat log %*

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/release
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/release b/lib/cordova-android/bin/templates/cordova/release
deleted file mode 100755
index 73d873e..0000000
--- a/lib/cordova-android/bin/templates/cordova/release
+++ /dev/null
@@ -1,24 +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.
-
-#!/bin/bash
-
-set -e
-
-CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
-
-bash "$CORDOVA_PATH"/cordova release

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/run
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/run b/lib/cordova-android/bin/templates/cordova/run
index 840a8d5..ec352b0 100755
--- a/lib/cordova-android/bin/templates/cordova/run
+++ b/lib/cordova-android/bin/templates/cordova/run
@@ -1,3 +1,4 @@
+#!/bin/bash
 # 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
@@ -15,10 +16,8 @@
 # specific language governing permissions and limitations
 # under the License.
 
-#!/bin/bash
-
 set -e
 
 CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
 
-bash "$CORDOVA_PATH"/cordova run
+bash "$CORDOVA_PATH"/lib/cordova run "$@"

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/templates/cordova/run.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/run.bat b/lib/cordova-android/bin/templates/cordova/run.bat
index 7c470ed..b1cab64 100644
--- a/lib/cordova-android/bin/templates/cordova/run.bat
+++ b/lib/cordova-android/bin/templates/cordova/run.bat
@@ -1 +1,2 @@
-%~dp0\cordova.bat run
+@ECHO OFF
+%~dp0\cordova.bat run %*
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/update
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/update b/lib/cordova-android/bin/update
index 0e86886..92ceda8 100755
--- a/lib/cordova-android/bin/update
+++ b/lib/cordova-android/bin/update
@@ -130,10 +130,17 @@ else
 fi
 
 # creating cordova folder and copying run/build/log/launch scripts
+mkdir "$PROJECT_PATH"/cordova
+mkdir "$PROJECT_PATH"/cordova/lib
 cp "$BUILD_PATH"/bin/templates/cordova/appinfo.jar "$PROJECT_PATH"/cordova/appinfo.jar
-cp "$BUILD_PATH"/bin/templates/cordova/cordova "$PROJECT_PATH"/cordova/cordova
 cp "$BUILD_PATH"/bin/templates/cordova/build "$PROJECT_PATH"/cordova/build
-cp "$BUILD_PATH"/bin/templates/cordova/release "$PROJECT_PATH"/cordova/release
 cp "$BUILD_PATH"/bin/templates/cordova/clean "$PROJECT_PATH"/cordova/clean
 cp "$BUILD_PATH"/bin/templates/cordova/log "$PROJECT_PATH"/cordova/log
 cp "$BUILD_PATH"/bin/templates/cordova/run "$PROJECT_PATH"/cordova/run
+cp "$BUILD_PATH"/bin/templates/cordova/lib/cordova "$PROJECT_PATH"/cordova/lib/cordova
+cp "$BUILD_PATH"/bin/templates/cordova/lib/install-device "$PROJECT_PATH"/cordova/lib/install-device
+cp "$BUILD_PATH"/bin/templates/cordova/lib/install-emulator "$PROJECT_PATH"/cordova/lib/install-emulator
+cp "$BUILD_PATH"/bin/templates/cordova/lib/list-devices "$PROJECT_PATH"/cordova/lib/list-devices
+cp "$BUILD_PATH"/bin/templates/cordova/lib/list-emulator-images "$PROJECT_PATH"/cordova/lib/list-emulator-images
+cp "$BUILD_PATH"/bin/templates/cordova/lib/list-started-emulators "$PROJECT_PATH"/cordova/lib/list-started-emulators
+cp "$BUILD_PATH"/bin/templates/cordova/lib/start-emulator "$PROJECT_PATH"/cordova/lib/start-emulator

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/bin/update.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/update.js b/lib/cordova-android/bin/update.js
index 244dcc1..748d602 100644
--- a/lib/cordova-android/bin/update.js
+++ b/lib/cordova-android/bin/update.js
@@ -183,11 +183,17 @@ if(fso.FolderExists(ROOT + '\\framework')) {
 createAppInfoJar();
 WScript.Echo("Copying cordova command tools...");
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\appinfo.jar ' + PROJECT_PATH + '\\cordova\\appinfo.jar /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\cordova.js ' + PROJECT_PATH + '\\cordova\\cordova.js /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\cordova.bat ' + PROJECT_PATH + '\\cordova\\cordova.bat /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\clean.bat ' + PROJECT_PATH + '\\cordova\\clean.bat /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\build.bat ' + PROJECT_PATH + '\\cordova\\build.bat /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\log.bat ' + PROJECT_PATH + '\\cordova\\log.bat /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\run.bat ' + PROJECT_PATH + '\\cordova\\run.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\cordova.js ' + PROJECT_PATH + '\\cordova\\lib\\cordova.js /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\install-device.bat ' + PROJECT_PATH + '\\cordova\\lib\\install-device.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\install-emulator.bat ' + PROJECT_PATH + '\\cordova\\lib\\install-emulator.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\list-emulator-images.bat ' + PROJECT_PATH + '\\cordova\\lib\\list-emulator-images.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\list-devices.bat ' + PROJECT_PATH + '\\cordova\\lib\\list-devices.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\list-started-emulators.bat ' + PROJECT_PATH + '\\cordova\\lib\\list-started-emulators.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\start-emulator.bat ' + PROJECT_PATH + '\\cordova\\lib\\start-emulator.bat /Y');
 
 cleanup();

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/assets/js/cordova.android.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/assets/js/cordova.android.js b/lib/cordova-android/framework/assets/js/cordova.android.js
index 93e85d1..2941307 100644
--- a/lib/cordova-android/framework/assets/js/cordova.android.js
+++ b/lib/cordova-android/framework/assets/js/cordova.android.js
@@ -1,8 +1,8 @@
 // Platform: android
 
-// commit 125dca530923a44a8f44f68f5e1970cbdd4e7faf
+// commit d0ffb852378ff018bac2f3b12c38098a19b8ce00
 
-// File generated at :: Mon Apr 01 2013 13:28:03 GMT-0700 (PDT)
+// File generated at :: Thu Apr 18 2013 15:10:54 GMT-0400 (EDT)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -219,6 +219,10 @@ var cordova = {
             }
             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);
             }
@@ -742,6 +746,7 @@ channel.createSticky('onDestroy');
 // Channels that must fire before "deviceready" is fired.
 channel.waitForInitialization('onCordovaReady');
 channel.waitForInitialization('onCordovaConnectionReady');
+channel.waitForInitialization('onDOMContentLoaded');
 
 module.exports = channel;
 
@@ -840,32 +845,27 @@ function androidExec(success, fail, service, action, args) {
     }
 
     var callbackId = service + cordova.callbackId++,
-        argsJson = JSON.stringify(args),
-        returnValue;
+        argsJson = JSON.stringify(args);
 
-    // TODO: Returning the payload of a synchronous call was deprecated in 2.2.0.
-    // Remove it after 6 months.
-    function captureReturnValue(value) {
-        returnValue = value;
-        success && success(value);
+    if (success || fail) {
+        cordova.callbacks[callbackId] = {success:success, fail:fail};
     }
 
-    cordova.callbacks[callbackId] = {success:captureReturnValue, 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);
-        androidExec.processMessages(messages);
-    }
-    if (cordova.callbacks[callbackId]) {
-        if (success || fail) {
-            cordova.callbacks[callbackId].success = success;
+        // 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 {
-            delete cordova.callbacks[callbackId];
+            androidExec.processMessages(messages);
         }
     }
-    return returnValue;
 }
 
 function pollOnce() {
@@ -981,30 +981,30 @@ function processMessage(message) {
 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) {
-            messages = messagesFromNative.shift();
+            // 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.
-            // TODO(agrieve): This is currently disabled on the Java side
-            // since it breaks returning the result in exec of synchronous
-            // plugins. Once we remove this ability, we can remove this comment.
             if (messages == '*') {
+                messagesFromNative.shift();
                 window.setTimeout(pollOnce, 0);
-                continue;
+                return;
             }
 
             var spaceIdx = messages.indexOf(' ');
             var msgLen = +messages.slice(0, spaceIdx);
             var message = messages.substr(spaceIdx + 1, msgLen);
             messages = messages.slice(spaceIdx + msgLen + 1);
-            // Put the remaining messages back into queue in case an exec()
-            // is made by the callback.
+            processMessage(message);
             if (messages) {
-                messagesFromNative.unshift(messages);
-            }
-
-            if (message) {
-                processMessage(message);
+                messagesFromNative[0] = messages;
+            } else {
+                messagesFromNative.shift();
             }
         }
     }
@@ -2398,7 +2398,7 @@ function initRead(reader, file) {
 
     if (typeof file == 'string') {
         // Deprecated in Cordova 2.4.
-        console.warning('Using a string argument with FileReader.readAs functions is deprecated.');
+        console.warn('Using a string argument with FileReader.readAs functions is deprecated.');
         reader._fileName = file;
     } else if (typeof file.fullPath == 'string') {
         reader._fileName = file.fullPath;
@@ -2756,7 +2756,7 @@ function getBasicAuthHeader(urlString) {
         var origin = protocol + url.host;
 
         // check whether there are the username:password credentials in the url
-        if (url.href.indexOf(origin) != 0) { // credentials found
+        if (url.href.indexOf(origin) !== 0) { // credentials found
             var atIndex = url.href.indexOf("@");
             credentials = url.href.substring(protocol.length, atIndex);
         }
@@ -2805,15 +2805,11 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
     var params = null;
     var chunkedMode = true;
     var headers = null;
-
+    var httpMethod = null;
     var basicAuthHeader = getBasicAuthHeader(server);
     if (basicAuthHeader) {
-        if (!options) {
-            options = new FileUploadOptions();
-        }
-        if (!options.headers) {
-            options.headers = {};
-        }
+        options = options || {};
+        options.headers = options.headers || {};
         options.headers[basicAuthHeader.name] = basicAuthHeader.value;
     }
 
@@ -2822,6 +2818,12 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
         fileName = options.fileName;
         mimeType = options.mimeType;
         headers = options.headers;
+        httpMethod = options.httpMethod || "POST";
+        if (httpMethod.toUpperCase() == "PUT"){
+            httpMethod = "PUT";
+        } else {
+            httpMethod = "POST";
+        }
         if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") {
             chunkedMode = options.chunkedMode;
         }
@@ -2848,7 +2850,7 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
             successCallback && successCallback(result);
         }
     };
-    exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id]);
+    exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id, httpMethod]);
 };
 
 /**
@@ -2866,12 +2868,8 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
 
     var basicAuthHeader = getBasicAuthHeader(source);
     if (basicAuthHeader) {
-        if (!options) {
-            options = {};
-        }
-        if (!options.headers) {
-            options.headers = {};
-        }
+        options = options || {};
+        options.headers = options.headers || {};
         options.headers[basicAuthHeader.name] = basicAuthHeader.value;
     }
 
@@ -2910,12 +2908,11 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
 };
 
 /**
- * Aborts the ongoing file transfer on this object
- * @param successCallback {Function}  Callback to be invoked upon success
- * @param errorCallback {Function}    Callback to be invoked upon error
+ * Aborts the ongoing file transfer on this object. The original error
+ * callback for the file transfer will be called if necessary.
  */
-FileTransfer.prototype.abort = function(successCallback, errorCallback) {
-    exec(successCallback, errorCallback, 'FileTransfer', 'abort', [this._id]);
+FileTransfer.prototype.abort = function() {
+    exec(null, null, 'FileTransfer', 'abort', [this._id]);
 };
 
 module.exports = FileTransfer;
@@ -2959,12 +2956,13 @@ define("cordova/plugin/FileUploadOptions", function(require, exports, module) {
  * @param headers {Object}   Keys are header names, values are header values. Multiple
  *                           headers of the same name are not supported.
  */
-var FileUploadOptions = function(fileKey, fileName, mimeType, params, headers) {
+var FileUploadOptions = function(fileKey, fileName, mimeType, params, headers, httpMethod) {
     this.fileKey = fileKey || null;
     this.fileName = fileName || null;
     this.mimeType = mimeType || null;
     this.params = params || null;
     this.headers = headers || null;
+    this.httpMethod = httpMethod || null;
 };
 
 module.exports = FileUploadOptions;
@@ -3299,6 +3297,7 @@ define("cordova/plugin/InAppBrowser", function(require, exports, module) {
 
 var exec = require('cordova/exec');
 var channel = require('cordova/channel');
+var modulemapper = require('cordova/modulemapper');
 
 function InAppBrowser() {
    this.channels = {
@@ -3327,6 +3326,26 @@ InAppBrowser.prototype = {
         if (eventname in this.channels) {
             this.channels[eventname].unsubscribe(f);
         }
+    },
+
+    executeScript: function(injectDetails, cb) {
+        if (injectDetails.code) {
+            exec(cb, null, "InAppBrowser", "injectScriptCode", [injectDetails.code, !!cb]);
+        } else if (injectDetails.file) {
+            exec(cb, null, "InAppBrowser", "injectScriptFile", [injectDetails.file, !!cb]);
+        } else {
+            throw new Error('executeScript requires exactly one of code or file to be specified');
+        }
+    },
+
+    insertCSS: function(injectDetails, cb) {
+        if (injectDetails.code) {
+            exec(cb, null, "InAppBrowser", "injectStyleCode", [injectDetails.code, !!cb]);
+        } else if (injectDetails.file) {
+            exec(cb, null, "InAppBrowser", "injectStyleFile", [injectDetails.file, !!cb]);
+        } else {
+            throw new Error('insertCSS requires exactly one of code or file to be specified');
+        }
     }
 };
 
@@ -3335,6 +3354,13 @@ module.exports = function(strUrl, strWindowName, strWindowFeatures) {
     var cb = function(eventname) {
        iab._eventHandler(eventname);
     };
+
+    // Don't catch calls that write to existing frames (e.g. named iframes).
+    if (window.frames && window.frames[strWindowName]) {
+        var origOpenFunc = modulemapper.getOriginalSymbol(window, 'open');
+        return origOpenFunc.apply(window, arguments);
+    }
+
     exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
     return iab;
 };
@@ -4858,7 +4884,7 @@ console.debug = function() {
 console.assert = function(expression) {
     if (expression) return;
 
-    var message = utils.vformat(arguments[1], [].slice.call(arguments, 2));
+    var message = logger.format.apply(logger.format, [].slice.call(arguments, 1));
     console.log("ASSERT: " + message);
 };
 
@@ -5958,10 +5984,10 @@ function logWithArgs(level, args) {
  * Parameters passed after message are used applied to
  * the message with utils.format()
  */
-logger.logLevel = function(level, message /* , ... */) {
+logger.logLevel = function(level /* , ... */) {
     // format the message with the parameters
-    var formatArgs = [].slice.call(arguments, 2);
-    message    = utils.vformat(message, formatArgs);
+    var formatArgs = [].slice.call(arguments, 1);
+    var message    = logger.format.apply(logger.format, formatArgs);
 
     if (LevelsMap[level] === null) {
         throw new Error("invalid logging level: " + level);
@@ -5996,6 +6022,92 @@ logger.logLevel = function(level, message /* , ... */) {
     }
 };
 
+
+/**
+ * Formats a string and arguments following it ala console.log()
+ *
+ * Any remaining arguments will be appended to the formatted string.
+ *
+ * for rationale, see FireBug's Console API:
+ *    http://getfirebug.com/wiki/index.php/Console_API
+ */
+logger.format = function(formatString, args) {
+    return __format(arguments[0], [].slice.call(arguments,1)).join(' ');
+};
+
+
+//------------------------------------------------------------------------------
+/**
+ * Formats a string and arguments following it ala vsprintf()
+ *
+ * format chars:
+ *   %j - format arg as JSON
+ *   %o - format arg as JSON
+ *   %c - format arg as ''
+ *   %% - replace with '%'
+ * any other char following % will format it's
+ * arg via toString().
+ *
+ * Returns an array containing the formatted string and any remaining
+ * arguments.
+ */
+function __format(formatString, args) {
+    if (formatString === null || formatString === undefined) return [""];
+    if (arguments.length == 1) return [formatString.toString()];
+
+    if (typeof formatString != "string")
+        formatString = formatString.toString();
+
+    var pattern = /(.*?)%(.)(.*)/;
+    var rest    = formatString;
+    var result  = [];
+
+    while (args.length) {
+        var match = pattern.exec(rest);
+        if (!match) break;
+
+        var arg   = args.shift();
+        rest = match[3];
+        result.push(match[1]);
+
+        if (match[2] == '%') {
+            result.push('%');
+            args.unshift(arg);
+            continue;
+        }
+
+        result.push(__formatted(arg, match[2]));
+    }
+
+    result.push(rest);
+
+    var remainingArgs = [].slice.call(args);
+    remainingArgs.unshift(result.join(''));
+    return remainingArgs;
+}
+
+function __formatted(object, formatChar) {
+
+    try {
+        switch(formatChar) {
+            case 'j':
+            case 'o': return JSON.stringify(object);
+            case 'c': return '';
+        }
+    }
+    catch (e) {
+        return "error JSON.stringify()ing argument: " + e;
+    }
+
+    if ((object === null) || (object === undefined)) {
+        return Object.prototype.toString.call(object);
+    }
+
+    return object.toString();
+}
+
+
+//------------------------------------------------------------------------------
 // when deviceready fires, log queued messages
 logger.__onDeviceReady = function() {
     if (DeviceReady) return;
@@ -6164,13 +6276,13 @@ module.exports = {
             console.log("Notification.confirm(string, function, string, string) is deprecated.  Use Notification.confirm(string, function, string, array).");
         }
 
-        // Android and iOS take an array of button label names.
+        // Some platforms take an array of button label names.
         // Other platforms take a comma separated list.
         // For compatibility, we convert to the desired type based on the platform.
-        if (platform.id == "android" || platform.id == "ios") {
+        if (platform.id == "android" || platform.id == "ios" || platform.id == "windowsphone") {
             if (typeof _buttonLabels === 'string') {
                 var buttonLabelString = _buttonLabels;
-                _buttonLabels = buttonLabelString.split(",");
+                _buttonLabels = _buttonLabels.split(","); // not crazy about changing the var type here
             }
         } else {
             if (Array.isArray(_buttonLabels)) {
@@ -6521,62 +6633,6 @@ utils.alert = function(msg) {
     }
 };
 
-/**
- * Formats a string and arguments following it ala sprintf()
- *
- * see utils.vformat() for more information
- */
-utils.format = function(formatString /* ,... */) {
-    var args = [].slice.call(arguments, 1);
-    return utils.vformat(formatString, args);
-};
-
-/**
- * Formats a string and arguments following it ala vsprintf()
- *
- * format chars:
- *   %j - format arg as JSON
- *   %o - format arg as JSON
- *   %c - format arg as ''
- *   %% - replace with '%'
- * any other char following % will format it's
- * arg via toString().
- *
- * for rationale, see FireBug's Console API:
- *    http://getfirebug.com/wiki/index.php/Console_API
- */
-utils.vformat = function(formatString, args) {
-    if (formatString === null || formatString === undefined) return "";
-    if (arguments.length == 1) return formatString.toString();
-    if (typeof formatString != "string") return formatString.toString();
-
-    var pattern = /(.*?)%(.)(.*)/;
-    var rest    = formatString;
-    var result  = [];
-
-    while (args.length) {
-        var arg   = args.shift();
-        var match = pattern.exec(rest);
-
-        if (!match) break;
-
-        rest = match[3];
-
-        result.push(match[1]);
-
-        if (match[2] == '%') {
-            result.push('%');
-            args.unshift(arg);
-            continue;
-        }
-
-        result.push(formatted(arg, match[2]));
-    }
-
-    result.push(rest);
-
-    return result.join('');
-};
 
 //------------------------------------------------------------------------------
 function UUIDcreatePart(length) {
@@ -6591,26 +6647,6 @@ function UUIDcreatePart(length) {
     return uuidpart;
 }
 
-//------------------------------------------------------------------------------
-function formatted(object, formatChar) {
-
-    try {
-        switch(formatChar) {
-            case 'j':
-            case 'o': return JSON.stringify(object);
-            case 'c': return '';
-        }
-    }
-    catch (e) {
-        return "error JSON.stringify()ing argument: " + e;
-    }
-
-    if ((object === null) || (object === undefined)) {
-        return Object.prototype.toString.call(object);
-    }
-
-    return object.toString();
-}
 
 });
 
@@ -6620,6 +6656,25 @@ window.cordova = require('cordova');
 // file: lib/scripts/bootstrap.js
 
 (function (context) {
+    var channel = require('cordova/channel');
+    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) {
@@ -6641,8 +6696,6 @@ window.cordova = require('cordova');
         context.navigator = replaceNavigator(context.navigator);
     }
 
-    var channel = require("cordova/channel");
-
     // _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.
@@ -6651,32 +6704,33 @@ window.cordova = require('cordova');
     }
 
     /**
-     * Create all cordova objects once page has fully loaded and native side is ready.
+     * Create all cordova objects once native side is ready.
      */
     channel.join(function() {
-        var builder = require('cordova/builder'),
-            platform = require('cordova/platform');
-
-        builder.buildIntoButDoNotClobber(platform.defaults, context);
-        builder.buildIntoAndClobber(platform.clobbers, context);
-        builder.buildIntoAndMerge(platform.merges, context);
-
         // Call the platform-specific initialization
-        platform.initialize();
+        require('cordova/platform').initialize();
 
         // Fire event to notify that all objects are created
         channel.onCordovaReady.fire();
 
-        // Fire onDeviceReady event once all constructors have run and
-        // cordova info has been received from native side.
+        // Fire onDeviceReady event once page has fully loaded, all
+        // constructors have run and cordova info has been received from native
+        // side.
+        // This join call is deliberately made after platform.initialize() in
+        // order that plugins may manipulate channel.deviceReadyChannelsArray
+        // if necessary.
         channel.join(function() {
             require('cordova').fireDocumentEvent('deviceready');
         }, channel.deviceReadyChannelsArray);
 
-    }, [ channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady ]);
+    }, platformInitChannelsArray);
 
 }(window));
 
+// file: lib/scripts/bootstrap-android.js
+
+require('cordova/channel').onNativeReady.fire();
+
 // file: lib/scripts/plugin_loader.js
 
 // Tries to load all plugins' js-modules.
@@ -6752,35 +6806,31 @@ window.cordova = require('cordova');
         }
     }
 
+
     // Try to XHR the cordova_plugins.json file asynchronously.
-    try { // we commented we were going to try, so let us actually try and catch 
+    try { // we commented we were going to try, so let us actually try and catch
         var xhr = new context.XMLHttpRequest();
-        xhr.onreadystatechange = function() {
-            if (this.readyState != 4) { // not DONE
-                return;
-            }
-
+        xhr.onload = function() {
             // If the response is a JSON string which composes an array, call handlePluginsObject.
             // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
-            if (this.status == 200) {
-                var obj = JSON.parse(this.responseText);
-                if (obj && obj instanceof Array && obj.length > 0) {
-                    handlePluginsObject(obj);
-                } else {
-                    finishPluginLoading();
-                }
+            var obj = JSON.parse(this.responseText);
+            if (obj && obj instanceof Array && obj.length > 0) {
+                handlePluginsObject(obj);
             } else {
                 finishPluginLoading();
             }
         };
+        xhr.onerror = function() {
+            finishPluginLoading();
+        };
         xhr.open('GET', 'cordova_plugins.json', true); // Async
         xhr.send();
     }
-    catch(err) {
+    catch(err){
         finishPluginLoading();
     }
 }(window));
 
 
 
-})();
+})();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/libs/commons-codec-1.7.jar
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/libs/commons-codec-1.7.jar b/lib/cordova-android/framework/libs/commons-codec-1.7.jar
deleted file mode 100644
index efa7f72..0000000
Binary files a/lib/cordova-android/framework/libs/commons-codec-1.7.jar and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/proguard-project.txt
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/proguard-project.txt b/lib/cordova-android/framework/proguard-project.txt
deleted file mode 100644
index f2fe155..0000000
--- a/lib/cordova-android/framework/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/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java b/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
index 22a9b94..426d250 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
@@ -42,6 +42,7 @@ import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Matrix;
 import android.graphics.Bitmap.CompressFormat;
+import android.graphics.Rect;
 import android.media.MediaScannerConnection;
 import android.media.MediaScannerConnection.MediaScannerConnectionClient;
 import android.net.Uri;
@@ -396,19 +397,21 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                             (destType == FILE_URI || destType == NATIVE_URI) && !this.correctOrientation) {
                         this.callbackContext.success(uri.toString());
                     } else {
+                        String uriString = uri.toString();
                         // Get the path to the image. Makes loading so much easier.
-                        String imagePath = FileHelper.getRealPath(uri, this.cordova);
-                        String mimeType = FileHelper.getMimeType(imagePath, this.cordova);
-                        // Log.d(LOG_TAG, "Real path = " + imagePath);
-                        // Log.d(LOG_TAG, "mime type = " + mimeType);
+                        String mimeType = FileHelper.getMimeType(uriString, this.cordova);
                         // If we don't have a valid image so quit.
-                        if (imagePath == null || mimeType == null || 
-                                !(mimeType.equalsIgnoreCase("image/jpeg") || mimeType.equalsIgnoreCase("image/png"))) {
+                        if (!("image/jpeg".equalsIgnoreCase(mimeType) || "image/png".equalsIgnoreCase(mimeType))) {
                         	Log.d(LOG_TAG, "I either have a null image path or bitmap");
                             this.failPicture("Unable to retrieve path to picture!");
                             return;
                         }
-                        Bitmap bitmap = getScaledBitmap(imagePath);
+                        Bitmap bitmap = null;
+                        try {
+                            bitmap = getScaledBitmap(uriString);
+                        } catch (IOException e) {
+                            e.printStackTrace();
+                        }
                         if (bitmap == null) {
                         	Log.d(LOG_TAG, "I either have a null image path or bitmap");
                             this.failPicture("Unable to create bitmap!");
@@ -416,14 +419,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                         }
 
                         if (this.correctOrientation) {
-                            String[] cols = { MediaStore.Images.Media.ORIENTATION };
-                            Cursor cursor = this.cordova.getActivity().getContentResolver().query(intent.getData(),
-                                    cols, null, null, null);
-                            if (cursor != null) {
-                                cursor.moveToPosition(0);
-                                rotate = cursor.getInt(0);
-                                cursor.close();
-                            }
+                            rotate = getImageOrientation(uri);
                             if (rotate != 0) {
                                 Matrix matrix = new Matrix();
                                 matrix.setRotate(rotate);
@@ -443,15 +439,17 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                                 try {
                                     // Create an ExifHelper to save the exif data that is lost during compression
                                     String resizePath = DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/resize.jpg";
+                                    // Some content: URIs do not map to file paths (e.g. picasa).
+                                    String realPath = FileHelper.getRealPath(uri, this.cordova);
                                     ExifHelper exif = new ExifHelper();
-                                    try {
-                                        if (this.encodingType == JPEG) {
-                                            exif.createInFile(FileHelper.getRealPath(uri, this.cordova));
+                                    if (realPath != null && this.encodingType == JPEG) {
+                                        try {
+                                            exif.createInFile(realPath);
                                             exif.readExifData();
                                             rotate = exif.getOrientation();
+                                        } catch (IOException e) {
+                                            e.printStackTrace();
                                         }
-                                    } catch (IOException e) {
-                                        e.printStackTrace();
                                     }
 
                                     OutputStream os = new FileOutputStream(resizePath);
@@ -459,7 +457,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                                     os.close();
 
                                     // Restore exif data to file
-                                    if (this.encodingType == JPEG) {
+                                    if (realPath != null && this.encodingType == JPEG) {
                                         exif.createOutFile(resizePath);
                                         exif.writeExifData();
                                     }
@@ -493,6 +491,19 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
         }
     }
 
+    private int getImageOrientation(Uri uri) {
+        String[] cols = { MediaStore.Images.Media.ORIENTATION };
+        Cursor cursor = cordova.getActivity().getContentResolver().query(uri,
+                cols, null, null, null);
+        int rotate = 0;
+        if (cursor != null) {
+            cursor.moveToPosition(0);
+            rotate = cursor.getInt(0);
+            cursor.close();
+        }
+        return rotate;
+    }
+
     /**
      * Figure out if the bitmap should be rotated. For instance if the picture was taken in
      * portrait mode
@@ -563,17 +574,18 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
      *
      * @param imagePath
      * @return
+     * @throws IOException 
      */
-    private Bitmap getScaledBitmap(String imagePath) {
+    private Bitmap getScaledBitmap(String imageUrl) throws IOException {
         // If no new width or height were specified return the original bitmap
         if (this.targetWidth <= 0 && this.targetHeight <= 0) {
-            return BitmapFactory.decodeFile(imagePath);
+            return BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova));
         }
 
         // figure out the original width and height of the image
         BitmapFactory.Options options = new BitmapFactory.Options();
         options.inJustDecodeBounds = true;
-        BitmapFactory.decodeFile(imagePath, options);
+        BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova), null, options);
         
         //CB-2292: WTF? Why is the width null?
         if(options.outWidth == 0 || options.outHeight == 0)
@@ -587,7 +599,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
         // Load in the smallest bitmap possible that is closest to the size we want
         options.inJustDecodeBounds = false;
         options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, this.targetWidth, this.targetHeight);
-        Bitmap unscaledBitmap = BitmapFactory.decodeFile(imagePath, options);
+        Bitmap unscaledBitmap = BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova), null, options);
         if (unscaledBitmap == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/Config.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/Config.java b/lib/cordova-android/framework/src/org/apache/cordova/Config.java
index f5de38d..594c2b2 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/Config.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/Config.java
@@ -171,7 +171,7 @@ public class Config {
                     LOG.i("CordovaLog", "Found start page location: %s", src);
 
                     if (src != null) {
-                        Pattern schemeRegex = Pattern.compile("^[a-z]+://");
+                        Pattern schemeRegex = Pattern.compile("^[a-z-]+://");
                         Matcher matcher = schemeRegex.matcher(src);
                         if (matcher.find()) {
                             startUrl = src;
@@ -220,19 +220,33 @@ public class Config {
             } else { // specific access
                 // check if subdomains should be included
                 // TODO: we should not add more domains if * has already been added
+                Pattern schemeRegex = Pattern.compile("^[a-z-]+://");
+                Matcher matcher = schemeRegex.matcher(origin);
                 if (subdomains) {
-                    // XXX making it stupid friendly for people who forget to include protocol/SSL
+                    // Check for http or https protocols
                     if (origin.startsWith("http")) {
                         this.whiteList.add(Pattern.compile(origin.replaceFirst("https?://", "^https?://(.*\\.)?")));
-                    } else {
+                    }
+                    // Check for other protocols
+                    else if(matcher.find()){
+                        this.whiteList.add(Pattern.compile("^" + origin.replaceFirst("//", "//(.*\\.)?")));
+                    }
+                    // XXX making it stupid friendly for people who forget to include protocol/SSL
+                    else {
                         this.whiteList.add(Pattern.compile("^https?://(.*\\.)?" + origin));
                     }
                     LOG.d(TAG, "Origin to allow with subdomains: %s", origin);
                 } else {
-                    // XXX making it stupid friendly for people who forget to include protocol/SSL
+                    // Check for http or https protocols
                     if (origin.startsWith("http")) {
                         this.whiteList.add(Pattern.compile(origin.replaceFirst("https?://", "^https?://")));
-                    } else {
+                    }
+                    // Check for other protocols
+                    else if(matcher.find()){
+                        this.whiteList.add(Pattern.compile("^" + origin));
+                    }
+                    // XXX making it stupid friendly for people who forget to include protocol/SSL
+                    else {
                         this.whiteList.add(Pattern.compile("^https?://" + origin));
                     }
                     LOG.d(TAG, "Origin to allow: %s", origin);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/CordovaLocationListener.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/CordovaLocationListener.java b/lib/cordova-android/framework/src/org/apache/cordova/CordovaLocationListener.java
old mode 100755
new mode 100644
index 7b7a9f7..01c828b
--- a/lib/cordova-android/framework/src/org/apache/cordova/CordovaLocationListener.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CordovaLocationListener.java
@@ -22,6 +22,8 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
 
 import org.apache.cordova.api.CallbackContext;
 
@@ -42,6 +44,8 @@ public class CordovaLocationListener implements LocationListener {
 
     public HashMap<String, CallbackContext> watches = new HashMap<String, CallbackContext>();
     private List<CallbackContext> callbacks = new ArrayList<CallbackContext>();
+    
+    private Timer timer = null;
 
     private String TAG = "[Cordova Location Listener]";
 
@@ -52,11 +56,12 @@ public class CordovaLocationListener implements LocationListener {
     }
 
     protected void fail(int code, String message) {
+    	this.cancelTimer();
         for (CallbackContext callbackContext: this.callbacks)
         {
-            this.owner.fail(code, message, callbackContext);
+            this.owner.fail(code, message, callbackContext, false);
         }
-        if(this.owner.isGlobalListener(this))
+        if(this.owner.isGlobalListener(this) && this.watches.size() == 0)
         {
         	Log.d(TAG, "Stopping global listener");
         	this.stop();
@@ -65,16 +70,17 @@ public class CordovaLocationListener implements LocationListener {
 
         Iterator<CallbackContext> it = this.watches.values().iterator();
         while (it.hasNext()) {
-            this.owner.fail(code, message, it.next());
+            this.owner.fail(code, message, it.next(), true);
         }
     }
 
     private void win(Location loc) {
+    	this.cancelTimer();
         for (CallbackContext callbackContext: this.callbacks)
         {
-            this.owner.win(loc, callbackContext);
+            this.owner.win(loc, callbackContext, false);
         }
-        if(this.owner.isGlobalListener(this))
+        if(this.owner.isGlobalListener(this) && this.watches.size() == 0)
         {
         	Log.d(TAG, "Stopping global listener");
         	this.stop();
@@ -83,7 +89,7 @@ public class CordovaLocationListener implements LocationListener {
 
         Iterator<CallbackContext> it = this.watches.values().iterator();
         while (it.hasNext()) {
-            this.owner.win(loc, it.next());
+            this.owner.win(loc, it.next(), true);
         }
     }
 
@@ -155,8 +161,12 @@ public class CordovaLocationListener implements LocationListener {
             this.start();
         }
     }
-    public void addCallback(CallbackContext callbackContext) {
-        this.callbacks.add(callbackContext);
+    public void addCallback(CallbackContext callbackContext, int timeout) {
+    	if(this.timer == null) {
+    		this.timer = new Timer();
+    	}
+    	this.timer.schedule(new LocationTimeoutTask(callbackContext, this), timeout);
+        this.callbacks.add(callbackContext);        
         if (this.size() == 1) {
             this.start();
         }
@@ -173,7 +183,7 @@ public class CordovaLocationListener implements LocationListener {
     /**
      * Destroy listener.
      */
-    public void destroy() {
+    public void destroy() {    	
         this.stop();
     }
 
@@ -199,9 +209,43 @@ public class CordovaLocationListener implements LocationListener {
      * Stop receiving location updates.
      */
     private void stop() {
+    	this.cancelTimer();
         if (this.running) {
             this.locationManager.removeUpdates(this);
             this.running = false;
         }
     }
+    
+    private void cancelTimer() {
+    	if(this.timer != null) {
+    		this.timer.cancel();
+        	this.timer.purge();
+        	this.timer = null;
+    	}
+    }
+    
+    private class LocationTimeoutTask extends TimerTask {
+    	
+    	private CallbackContext callbackContext = null;
+    	private CordovaLocationListener listener = null;
+    	
+    	public LocationTimeoutTask(CallbackContext callbackContext, CordovaLocationListener listener) {
+    		this.callbackContext = callbackContext;
+    		this.listener = listener;
+    	}
+
+		@Override
+		public void run() {
+			for (CallbackContext callbackContext: listener.callbacks) {
+				if(this.callbackContext == callbackContext) {
+					listener.callbacks.remove(callbackContext);
+					break;
+				}
+			}
+			
+			if(listener.size() == 0) {
+				listener.stop();
+			}
+		}    	
+    }
 }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebView.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebView.java b/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebView.java
index e653a95..5dd061e 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebView.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebView.java
@@ -24,6 +24,7 @@ import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Stack;
+import java.util.regex.Pattern;
 
 import org.apache.cordova.Config;
 import org.apache.cordova.api.CordovaInterface;
@@ -237,7 +238,11 @@ public class CordovaWebView extends WebView {
         // Set the nav dump for HTC 2.x devices (disabling for ICS, deprecated entirely for Jellybean 4.2)
         try {
             Method gingerbread_getMethod =  WebSettings.class.getMethod("setNavDump", new Class[] { boolean.class });
-            if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
+            
+            String manufacturer = android.os.Build.MANUFACTURER;
+            Log.d(TAG, "CordovaWebView is running on device made by: " + manufacturer);
+            if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB &&
+                    android.os.Build.MANUFACTURER.contains("HTC"))
             {
                 gingerbread_getMethod.invoke(settings, true);
             }
@@ -262,11 +267,8 @@ public class CordovaWebView extends WebView {
         // Enable database
         // We keep this disabled because we use or shim to get around DOM_EXCEPTION_ERROR_16
         String databasePath = this.cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
-        if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
-        {
-            settings.setDatabaseEnabled(true);
-            settings.setDatabasePath(databasePath);
-        }
+        settings.setDatabaseEnabled(true);
+        settings.setDatabasePath(databasePath);
         
         settings.setGeolocationDatabasePath(databasePath);
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebViewClient.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebViewClient.java b/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebViewClient.java
index 4751fc3..4b00615 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebViewClient.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebViewClient.java
@@ -314,15 +314,6 @@ public class CordovaWebViewClient extends WebViewClient {
         // Clear timeout flag
         this.appView.loadUrlTimeout++;
 
-        // Try firing the onNativeReady event in JS. If it fails because the JS is
-        // not loaded yet then just set a flag so that the onNativeReady can be fired
-        // from the JS side when the JS gets to that code.
-        if (!url.equals("about:blank")) {
-            LOG.d(TAG, "Trying to fire onNativeReady");
-            this.appView.loadUrl("javascript:try{ cordova.require('cordova/channel').onNativeReady.fire();}catch(e){_nativeReady = true;}");
-            this.appView.postMessage("onNativeReady", null);
-        }
-
         // Broadcast message that page has loaded
         this.appView.postMessage("onPageFinished", url);
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/Device.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/Device.java b/lib/cordova-android/framework/src/org/apache/cordova/Device.java
index 0f828a1..aa316c5 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/Device.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/Device.java
@@ -77,7 +77,6 @@ public class Device extends CordovaPlugin {
             r.put("uuid", Device.uuid);
             r.put("version", this.getOSVersion());
             r.put("platform", Device.platform);
-            r.put("name", this.getProductName());
             r.put("cordova", Device.cordovaVersion);
             r.put("model", this.getModel());
             callbackContext.success(r);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/DroidGap.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/DroidGap.java b/lib/cordova-android/framework/src/org/apache/cordova/DroidGap.java
index d4296cb..bb895e2 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/DroidGap.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/DroidGap.java
@@ -51,6 +51,7 @@ import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager;
+import android.widget.ImageView;
 import android.webkit.ValueCallback;
 import android.webkit.WebViewClient;
 import android.widget.LinearLayout;
@@ -717,7 +718,7 @@ public class DroidGap extends Activity implements CordovaInterface {
             appView.handleDestroy();
         }
         else {
-            this.endActivity();
+            this.activityState = ACTIVITY_EXITING; 
         }
     }
 
@@ -1031,7 +1032,13 @@ public class DroidGap extends Activity implements CordovaInterface {
                 root.setBackgroundColor(that.getIntegerProperty("backgroundColor", Color.BLACK));
                 root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
                         ViewGroup.LayoutParams.FILL_PARENT, 0.0F));
-                root.setBackgroundResource(that.splashscreen);
+                // We want the splashscreen to keep its ratio, 
+                // for this we need to use an ImageView and not simply the background of the LinearLayout
+                ImageView splashscreenView = new ImageView(that.getActivity());
+                splashscreenView.setImageResource(that.splashscreen);
+                splashscreenView.setScaleType(ImageView.ScaleType.CENTER_CROP); // similar to the background-size:cover CSS property
+                splashscreenView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
+                root.addView(splashscreenView);
 
                 // Create and show the dialog
                 splashDialog = new Dialog(that, android.R.style.Theme_Translucent_NoTitleBar);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/ExposedJsApi.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/ExposedJsApi.java b/lib/cordova-android/framework/src/org/apache/cordova/ExposedJsApi.java
index 48e7102..7702d35 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/ExposedJsApi.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/ExposedJsApi.java
@@ -20,6 +20,7 @@ package org.apache.cordova;
 
 import android.webkit.JavascriptInterface;
 import org.apache.cordova.api.PluginManager;
+import org.apache.cordova.api.PluginResult;
 import org.json.JSONException;
 
 /**
@@ -39,6 +40,12 @@ import org.json.JSONException;
 
     @JavascriptInterface
     public String exec(String service, String action, String callbackId, String arguments) throws JSONException {
+        // If the arguments weren't received, send a message back to JS.  It will switch bridge modes and try again.  See CB-2666.
+        // We send a message meant specifically for this case.  It starts with "@" so no other message can be encoded into the same string.
+        if (arguments == null) {
+            return "@Null arguments.";
+        }
+
         jsMessageQueue.setPaused(true);
         try {
             boolean wasSync = pluginManager.exec(service, action, callbackId, arguments);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/FileHelper.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/FileHelper.java b/lib/cordova-android/framework/src/org/apache/cordova/FileHelper.java
index c10ed96..8b446b0 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/FileHelper.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/FileHelper.java
@@ -28,6 +28,8 @@ import org.apache.cordova.api.LOG;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.URLConnection;
+import java.util.Locale;
 
 public class FileHelper {
     private static final String LOG_TAG = "FileUtils";
@@ -92,7 +94,8 @@ public class FileHelper {
             Uri uri = Uri.parse(uriString);
             return cordova.getActivity().getContentResolver().openInputStream(uri);
         } else if (uriString.startsWith("file:///android_asset/")) {
-            String relativePath = uriString.substring(22);
+            Uri uri = Uri.parse(uriString);
+            String relativePath = uri.getPath().substring(15);
             return cordova.getActivity().getAssets().open(relativePath);
         } else {
             return new FileInputStream(getRealPath(uriString, cordova));
@@ -122,14 +125,18 @@ public class FileHelper {
     public static String getMimeType(String uriString, CordovaInterface cordova) {
         String mimeType = null;
 
+        Uri uri = Uri.parse(uriString);
         if (uriString.startsWith("content://")) {
-            Uri uri = Uri.parse(uriString);
             mimeType = cordova.getActivity().getContentResolver().getType(uri);
         } else {
-            // MimeTypeMap.getFileExtensionFromUrl has a bug that occurs when the filename has a space, so we encode it.
-            // We also convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
-            String encodedUriString = uriString.replace(" ", "%20").toLowerCase();
-            String extension = MimeTypeMap.getFileExtensionFromUrl(encodedUriString);
+            // MimeTypeMap.getFileExtensionFromUrl() fails when there are query parameters.
+            String extension = uri.getPath();
+            int lastDot = extension.lastIndexOf('.');
+            if (lastDot != -1) {
+                extension = extension.substring(lastDot + 1);
+            }
+            // Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
+            extension = extension.toLowerCase();
             if (extension.equals("3ga")) {
                 mimeType = "audio/3gpp";
             } else {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java b/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java
index dba29af..c1ca15c 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java
@@ -41,6 +41,8 @@ import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.Inflater;
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
@@ -100,10 +102,83 @@ public class FileTransfer extends CordovaPlugin {
     }
 
     /**
+     * Adds an interface method to an InputStream to return the number of bytes
+     * read from the raw stream. This is used to track total progress against
+     * the HTTP Content-Length header value from the server.
+     */
+    private static abstract class TrackingInputStream extends FilterInputStream {
+    	public TrackingInputStream(final InputStream in) {
+    		super(in);
+    	}
+        public abstract long getTotalRawBytesRead();
+	}
+
+    private static class ExposedGZIPInputStream extends GZIPInputStream {
+	    public ExposedGZIPInputStream(final InputStream in) throws IOException {
+	    	super(in);
+	    }
+	    public Inflater getInflater() {
+	    	return inf;
+	    }
+	}
+
+    /**
+     * Provides raw bytes-read tracking for a GZIP input stream. Reports the
+     * total number of compressed bytes read from the input, rather than the
+     * number of uncompressed bytes.
+     */
+    private static class TrackingGZIPInputStream extends TrackingInputStream {
+    	private ExposedGZIPInputStream gzin;
+	    public TrackingGZIPInputStream(final ExposedGZIPInputStream gzin) throws IOException {
+	    	super(gzin);
+	    	this.gzin = gzin;
+	    }
+	    public long getTotalRawBytesRead() {
+	    	return gzin.getInflater().getBytesRead();
+	    }
+	}
+
+    /**
+     * Provides simple total-bytes-read tracking for an existing InputStream
+     */
+    private static class TrackingHTTPInputStream extends TrackingInputStream {
+        private long bytesRead = 0;
+        public TrackingHTTPInputStream(InputStream stream) {
+            super(stream);
+        }
+
+        private int updateBytesRead(int newBytesRead) {
+        	if (newBytesRead != -1) {
+        		bytesRead += newBytesRead;
+        	}
+        	return newBytesRead;
+        }
+
+        @Override
+        public int read() throws IOException {
+            return updateBytesRead(super.read());
+        }
+
+        @Override
+        public int read(byte[] buffer) throws IOException {
+            return updateBytesRead(super.read(buffer));
+        }
+
+        @Override
+        public int read(byte[] bytes, int offset, int count) throws IOException {
+            return updateBytesRead(super.read(bytes, offset, count));
+        }
+
+        public long getTotalRawBytesRead() {
+        	return bytesRead;
+        }
+    }
+
+    /**
      * Works around a bug on Android 2.3.
      * http://code.google.com/p/android/issues/detail?id=14562
      */
-    private static final class DoneHandlerInputStream extends FilterInputStream {
+    private static final class DoneHandlerInputStream extends TrackingHTTPInputStream {
         private boolean done;
         
         public DoneHandlerInputStream(InputStream stream) {
@@ -204,6 +279,7 @@ public class FileTransfer extends CordovaPlugin {
         // Look for headers on the params map for backwards compatibility with older Cordova versions.
         final JSONObject headers = args.optJSONObject(8) == null ? params.optJSONObject("headers") : args.optJSONObject(8);
         final String objectId = args.getString(9);
+        final String httpMethod = getArgument(args, 10, "POST");
 
         Log.d(LOG_TAG, "fileKey: " + fileKey);
         Log.d(LOG_TAG, "fileName: " + fileName);
@@ -213,6 +289,7 @@ public class FileTransfer extends CordovaPlugin {
         Log.d(LOG_TAG, "chunkedMode: " + chunkedMode);
         Log.d(LOG_TAG, "headers: " + headers);
         Log.d(LOG_TAG, "objectId: " + objectId);
+        Log.d(LOG_TAG, "httpMethod: " + httpMethod);
         
         final URL url;
         try {
@@ -280,7 +357,7 @@ public class FileTransfer extends CordovaPlugin {
                     conn.setUseCaches(false);
 
                     // Use a post method.
-                    conn.setRequestMethod("POST");
+                    conn.setRequestMethod(httpMethod);
                     conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);
 
                     // Set the cookies on the response
@@ -407,7 +484,7 @@ public class FileTransfer extends CordovaPlugin {
                     int responseCode = conn.getResponseCode();
                     Log.d(LOG_TAG, "response code: " + responseCode);
                     Log.d(LOG_TAG, "response headers: " + conn.getHeaderFields());
-                    InputStream inStream = null;
+                    TrackingInputStream inStream = null;
                     try {
                         inStream = getInputStream(conn);
                         synchronized (context) {
@@ -483,11 +560,15 @@ public class FileTransfer extends CordovaPlugin {
         }
     }
 
-    private static InputStream getInputStream(URLConnection conn) throws IOException {
+    private static TrackingInputStream getInputStream(URLConnection conn) throws IOException {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
             return new DoneHandlerInputStream(conn.getInputStream());
         }
-        return conn.getInputStream();
+        String encoding = conn.getContentEncoding();
+        if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
+        	return new TrackingGZIPInputStream(new ExposedGZIPInputStream(conn.getInputStream()));
+        }
+        return new TrackingHTTPInputStream(conn.getInputStream());
     }
 
     // always verify the host - don't check for certificate
@@ -698,6 +779,9 @@ public class FileTransfer extends CordovaPlugin {
                     {
                         connection.setRequestProperty("cookie", cookie);
                     }
+                    
+                    // This must be explicitly set for gzip progress tracking to work.
+                    connection.setRequestProperty("Accept-Encoding", "gzip");
 
                     // Handle the other headers
                     if (headers != null) {
@@ -709,14 +793,15 @@ public class FileTransfer extends CordovaPlugin {
                     Log.d(LOG_TAG, "Download file:" + url);
 
                     FileProgressResult progress = new FileProgressResult();
-                    if (connection.getContentEncoding() == null) {
-                        // Only trust content-length header if no gzip etc
+                    if (connection.getContentEncoding() == null || connection.getContentEncoding().equalsIgnoreCase("gzip")) {
+                        // Only trust content-length header if we understand
+                        // the encoding -- identity or gzip
                         progress.setLengthComputable(true);
                         progress.setTotal(connection.getContentLength());
                     }
                     
                     FileOutputStream outputStream = null;
-                    InputStream inputStream = null;
+                    TrackingInputStream inputStream = null;
                     
                     try {
                         inputStream = getInputStream(connection);
@@ -731,12 +816,10 @@ public class FileTransfer extends CordovaPlugin {
                         // write bytes to file
                         byte[] buffer = new byte[MAX_BUFFER_SIZE];
                         int bytesRead = 0;
-                        long totalBytes = 0;
                         while ((bytesRead = inputStream.read(buffer)) > 0) {
                             outputStream.write(buffer, 0, bytesRead);
-                            totalBytes += bytesRead;
                             // Send a progress event.
-                            progress.setLoaded(totalBytes);
+                            progress.setLoaded(inputStream.getTotalRawBytesRead());
                             PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
                             progressResult.setKeepCallback(true);
                             context.sendPluginResult(progressResult);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/GeoBroker.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/GeoBroker.java b/lib/cordova-android/framework/src/org/apache/cordova/GeoBroker.java
old mode 100755
new mode 100644
index e7cdce0..4a07b73
--- a/lib/cordova-android/framework/src/org/apache/cordova/GeoBroker.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/GeoBroker.java
@@ -38,7 +38,7 @@ import android.location.LocationManager;
 public class GeoBroker extends CordovaPlugin {
     private GPSListener gpsListener;
     private NetworkListener networkListener;
-    private LocationManager locationManager;
+    private LocationManager locationManager;    
 
     /**
      * Constructor.
@@ -73,7 +73,7 @@ public class GeoBroker extends CordovaPlugin {
                     PluginResult result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(last));
                     callbackContext.sendPluginResult(result);
                 } else {
-                    this.getCurrentLocation(callbackContext, enableHighAccuracy);
+                    this.getCurrentLocation(callbackContext, enableHighAccuracy, args.optInt(2, 60000));
                 }
             }
             else if (action.equals("addWatch")) {
@@ -102,11 +102,11 @@ public class GeoBroker extends CordovaPlugin {
         this.networkListener.clearWatch(id);
     }
 
-    private void getCurrentLocation(CallbackContext callbackContext, boolean enableHighAccuracy) {
+    private void getCurrentLocation(CallbackContext callbackContext, boolean enableHighAccuracy, int timeout) {
         if (enableHighAccuracy) {
-            this.gpsListener.addCallback(callbackContext);
+            this.gpsListener.addCallback(callbackContext, timeout);
         } else {
-            this.networkListener.addCallback(callbackContext);
+            this.networkListener.addCallback(callbackContext, timeout);
         }
     }
 
@@ -160,8 +160,9 @@ public class GeoBroker extends CordovaPlugin {
         return o;
     }
 
-    public void win(Location loc, CallbackContext callbackContext) {
-        PluginResult result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(loc));
+    public void win(Location loc, CallbackContext callbackContext, boolean keepCallback) {
+    	PluginResult result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(loc));
+    	result.setKeepCallback(keepCallback);
         callbackContext.sendPluginResult(result);
     }
 
@@ -172,7 +173,7 @@ public class GeoBroker extends CordovaPlugin {
      * @param msg			The error message
      * @throws JSONException 
      */
-    public void fail(int code, String msg, CallbackContext callbackContext) {
+    public void fail(int code, String msg, CallbackContext callbackContext, boolean keepCallback) {
         JSONObject obj = new JSONObject();
         String backup = null;
         try {
@@ -189,6 +190,7 @@ public class GeoBroker extends CordovaPlugin {
             result = new PluginResult(PluginResult.Status.ERROR, backup);
         }
 
+        result.setKeepCallback(keepCallback);
         callbackContext.sendPluginResult(result);
     }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/71fb3725/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java b/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
index 2142714..375282e 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
@@ -24,11 +24,12 @@ import java.io.InputStream;
 import org.apache.cordova.api.CordovaInterface;
 import org.apache.cordova.api.LOG;
 
-import android.content.res.AssetManager;
-import android.net.Uri;
+import android.annotation.TargetApi;
+import android.os.Build;
 import android.webkit.WebResourceResponse;
 import android.webkit.WebView;
 
+@TargetApi(Build.VERSION_CODES.HONEYCOMB)
 public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
 
 
@@ -43,34 +44,20 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
     @Override
     public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
         if(url.contains("?") || url.contains("#") || needsIceCreamSpaceInAssetUrlFix(url)){
-            return generateWebResourceResponse(url);
-        } else {
-            return super.shouldInterceptRequest(view, url);
+            WebResourceResponse ret = generateWebResourceResponse(url);
+            if (ret != null) {
+                return ret;
+            }
         }
+        return super.shouldInterceptRequest(view, url);
     }
 
     private WebResourceResponse generateWebResourceResponse(String url) {
-        final String ANDROID_ASSET = "file:///android_asset/";
-        if (url.startsWith(ANDROID_ASSET)) {
-            String niceUrl = url;
-            niceUrl = url.replaceFirst(ANDROID_ASSET, "");
-            if(niceUrl.contains("?")){
-                niceUrl = niceUrl.split("\\?")[0];
-            }
-            else if(niceUrl.contains("#"))
-            {
-                niceUrl = niceUrl.split("#")[0];
-            }
-
-            String mimetype = null;
-            if(niceUrl.endsWith(".html")){
-                mimetype = "text/html";
-            }
+        if (url.startsWith("file:///android_asset/")) {
+            String mimetype = FileHelper.getMimeType(url, cordova);
 
             try {
-                AssetManager assets = cordova.getActivity().getAssets();
-                Uri uri = Uri.parse(niceUrl);
-                InputStream stream = assets.open(uri.getPath(), AssetManager.ACCESS_STREAMING);
+                InputStream stream = FileHelper.getInputStreamFromUriString(url, cordova);
                 WebResourceResponse response = new WebResourceResponse(mimetype, "UTF-8", stream);
                 return response;
             } catch (IOException e) {


[26/43] git commit: [src] Remove unused platform parsers from compile command.

Posted by an...@apache.org.
[src] Remove unused platform parsers from compile command.


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

Branch: refs/heads/master
Commit: 56e4563705e01b90c7f7364c5ed5cb761e1488e9
Parents: 56b4247
Author: Michael Brooks <mi...@michaelbrooks.ca>
Authored: Wed Apr 17 13:58:54 2013 -0600
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu May 9 14:26:06 2013 -0700

----------------------------------------------------------------------
 src/compile.js |    3 ---
 1 files changed, 0 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56e45637/src/compile.js
----------------------------------------------------------------------
diff --git a/src/compile.js b/src/compile.js
index 0e8951a..cc8dd5c 100644
--- a/src/compile.js
+++ b/src/compile.js
@@ -23,9 +23,6 @@ var cordova_util      = require('./util'),
     fs                = require('fs'),
     shell             = require('shelljs'),
     et                = require('elementtree'),
-    android_parser    = require('./metadata/android_parser'),
-    blackberry_parser = require('./metadata/blackberry_parser'),
-    ios_parser        = require('./metadata/ios_parser'),
     hooker            = require('./hooker'),
     n                 = require('ncallbacks'),
     prompt            = require('prompt'),


[43/43] git commit: Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/cordova-cli

Posted by an...@apache.org.
Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/cordova-cli

Conflicts:
	src/plugin_loader.js


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

Branch: refs/heads/master
Commit: 51901bd9f22127ca283df5fa4e06611cbb59359b
Parents: 164d064 72cca5e
Author: Anis Kadri <an...@gmail.com>
Authored: Thu May 9 15:57:04 2013 -0700
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu May 9 15:57:04 2013 -0700

----------------------------------------------------------------------

----------------------------------------------------------------------



[04/43] git commit: Fix cordova plugin add with trailing slash

Posted by an...@apache.org.
Fix cordova plugin add with trailing slash


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

Branch: refs/heads/master
Commit: 10ad93df05caeec04dc7bcdfe05dc682b75075a5
Parents: fb7cbc6
Author: Braden Shepherdson <br...@gmail.com>
Authored: Tue Mar 26 14:55:28 2013 -0400
Committer: Braden Shepherdson <br...@gmail.com>
Committed: Tue Mar 26 14:55:28 2013 -0400

----------------------------------------------------------------------
 src/plugin.js |   13 +++++++++----
 1 files changed, 9 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/10ad93df/src/plugin.js
----------------------------------------------------------------------
diff --git a/src/plugin.js b/src/plugin.js
index 03442eb..f2638f5 100644
--- a/src/plugin.js
+++ b/src/plugin.js
@@ -50,11 +50,14 @@ module.exports = function plugin(command, targets, callback) {
     var pluginPath, plugins, names = [];
     pluginPath = path.join(projectRoot, 'plugins');
     plugins = ls(pluginPath);
-    if (targets) { 
+    if (targets) {
         if (!(targets instanceof Array)) targets = [targets];
         targets.forEach(function(target) {
-            var targetName = target.substr(target.lastIndexOf('/') + 1);
-            if (targetName[targetName.length-1] == '/') targetName = targetName.substr(0, targetName.length-1);
+            if (target[target.length - 1] == path.sep) {
+                target = target.substring(0, target.length - 1);
+            }
+
+            var targetName = target.substr(target.lastIndexOf(path.sep) + 1);
             names.push(targetName);
         });
     }
@@ -75,7 +78,9 @@ module.exports = function plugin(command, targets, callback) {
                 var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'plugman.js');
                 var pluginsDir = path.join(projectRoot, 'plugins');
 
-                var lastSlash = target.lastIndexOf('/', target.length - 2);
+                if (target[target.length - 1] == path.sep) {
+                    target = target.substring(0, target.length - 1);
+                }
 
                 // Fetch the plugin first.
                 var cmd = util.format('%s --fetch --plugin "%s" --plugins_dir "%s"', cli, target, pluginsDir);


[25/43] git commit: updated version to 2.6.0

Posted by an...@apache.org.
updated version to 2.6.0


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

Branch: refs/heads/master
Commit: 56b42470b4884c7415d81778f38023bf1ef983c0
Parents: 72e7265
Author: Steven Gill <st...@gmail.com>
Authored: Tue Apr 9 12:25:45 2013 -0700
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu May 9 14:26:06 2013 -0700

----------------------------------------------------------------------
 VERSION                                            |    2 +-
 lib/cordova-android/VERSION                        |    2 +-
 .../bin/templates/cordova/appinfo.jar              |  Bin 1574 -> 1574 bytes
 .../bin/templates/project/assets/www/index.html    |    4 +-
 .../framework/assets/js/cordova.android.js         |   45 ++++---
 .../framework/assets/www/index.html                |    2 +-
 .../src/org/apache/cordova/CameraLauncher.java     |   12 +-
 .../framework/src/org/apache/cordova/Device.java   |    2 +-
 .../src/org/apache/cordova/InAppBrowser.java       |   17 +++-
 .../src/org/apache/cordova/api/PluginManager.java  |    2 +
 lib/cordova-android/test/res/xml/cordova.xml       |   37 -----
 lib/cordova-android/test/res/xml/plugins.xml       |   39 ------
 lib/cordova-blackberry/VERSION                     |    2 +-
 .../bin/templates/project/www/VERSION              |    2 +-
 .../bin/templates/project/www/index.html           |    2 +-
 .../ext/src/org/apache/cordova/device/Device.java  |    2 +-
 .../src/org/apache/cordova/file/FileManager.java   |   11 ++-
 .../javascript/cordova.blackberry.js               |   47 ++++---
 lib/cordova-ios/CordovaLib/Classes/CDVCamera.m     |   71 ++--------
 .../CordovaLib/Classes/CDVJpegHeaderWriter.h       |    2 +
 .../CordovaLib/Classes/CDVJpegHeaderWriter.m       |  106 +++++++++++----
 .../CordovaLib/Classes/CDVSplashScreen.m           |    7 +-
 lib/cordova-ios/CordovaLib/VERSION                 |    2 +-
 lib/cordova-ios/CordovaLib/cordova.ios.js          |   43 ++++---
 lib/cordova-ios/RELEASENOTES.md                    |    4 +
 lib/cordova-ios/bin/README.md                      |   29 ----
 26 files changed, 225 insertions(+), 269 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/VERSION
----------------------------------------------------------------------
diff --git a/VERSION b/VERSION
index 437459c..e70b452 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.5.0
+2.6.0

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-android/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-android/VERSION b/lib/cordova-android/VERSION
index f47de85..e70b452 100644
--- a/lib/cordova-android/VERSION
+++ b/lib/cordova-android/VERSION
@@ -1 +1 @@
-2.6.0rc1
+2.6.0

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-android/bin/templates/cordova/appinfo.jar
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/appinfo.jar b/lib/cordova-android/bin/templates/cordova/appinfo.jar
index 7f8ac60..390bb6d 100644
Binary files a/lib/cordova-android/bin/templates/cordova/appinfo.jar and b/lib/cordova-android/bin/templates/cordova/appinfo.jar differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-android/bin/templates/project/assets/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/project/assets/www/index.html b/lib/cordova-android/bin/templates/project/assets/www/index.html
index 5596f62..4d39cf3 100644
--- a/lib/cordova-android/bin/templates/project/assets/www/index.html
+++ b/lib/cordova-android/bin/templates/project/assets/www/index.html
@@ -19,7 +19,7 @@
 -->
 <html>
     <head>
-        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+        <meta charset="utf-8" />
         <meta name="format-detection" content="telephone=no" />
         <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" />
@@ -33,7 +33,7 @@
                 <p class="event received">Device is Ready</p>
             </div>
         </div>
-        <script type="text/javascript" src="cordova-2.6.0rc1.js"></script>
+        <script type="text/javascript" src="cordova-2.6.0.js"></script>
         <script type="text/javascript" src="js/index.js"></script>
         <script type="text/javascript">
             app.initialize();

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-android/framework/assets/js/cordova.android.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/assets/js/cordova.android.js b/lib/cordova-android/framework/assets/js/cordova.android.js
index a0c3278..93e85d1 100644
--- a/lib/cordova-android/framework/assets/js/cordova.android.js
+++ b/lib/cordova-android/framework/assets/js/cordova.android.js
@@ -1,8 +1,8 @@
 // Platform: android
 
-// commit 47593b2bc1dba9bf46545b1da24577f937966e12
+// commit 125dca530923a44a8f44f68f5e1970cbdd4e7faf
 
-// File generated at :: Thu Mar 21 2013 10:49:00 GMT-0700 (PDT)
+// File generated at :: Mon Apr 01 2013 13:28:03 GMT-0700 (PDT)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -6753,29 +6753,34 @@ window.cordova = require('cordova');
     }
 
     // Try to XHR the cordova_plugins.json file asynchronously.
-    var xhr = new context.XMLHttpRequest();
-    xhr.onreadystatechange = function() {
-        if (this.readyState != 4) { // not DONE
-            return;
-        }
+    try { // we commented we were going to try, so let us actually try and catch 
+        var xhr = new context.XMLHttpRequest();
+        xhr.onreadystatechange = function() {
+            if (this.readyState != 4) { // not DONE
+                return;
+            }
 
-        // If the response is a JSON string which composes an array, call handlePluginsObject.
-        // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
-        if (this.status == 200) {
-            var obj = JSON.parse(this.responseText);
-            if (obj && obj instanceof Array && obj.length > 0) {
-                handlePluginsObject(obj);
+            // If the response is a JSON string which composes an array, call handlePluginsObject.
+            // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
+            if (this.status == 200) {
+                var obj = JSON.parse(this.responseText);
+                if (obj && obj instanceof Array && obj.length > 0) {
+                    handlePluginsObject(obj);
+                } else {
+                    finishPluginLoading();
+                }
             } else {
                 finishPluginLoading();
             }
-        } else {
-            finishPluginLoading();
-        }
-    };
-    xhr.open('GET', 'cordova_plugins.json', true); // Async
-    xhr.send();
+        };
+        xhr.open('GET', 'cordova_plugins.json', true); // Async
+        xhr.send();
+    }
+    catch(err) {
+        finishPluginLoading();
+    }
 }(window));
 
 
 
-})();
\ No newline at end of file
+})();

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-android/framework/assets/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/assets/www/index.html b/lib/cordova-android/framework/assets/www/index.html
index 3b15a4e..1caeb8a 100644
--- a/lib/cordova-android/framework/assets/www/index.html
+++ b/lib/cordova-android/framework/assets/www/index.html
@@ -19,7 +19,7 @@
 <html>
   <head>
     <title></title>
-    <script src="cordova-2.6.0rc1.js"></script>
+    <script src="cordova-2.6.0.js"></script>
   </head>
   <body>
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java b/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
index 9473828..22a9b94 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
@@ -312,10 +312,12 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
 
                     // If sending filename back
                     else if (destType == FILE_URI || destType == NATIVE_URI) {
-                        if (!this.saveToPhotoAlbum) {
-                            uri = Uri.fromFile(new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), System.currentTimeMillis() + ".jpg"));
+                        if (this.saveToPhotoAlbum) {
+                            Uri inputUri = getUriFromMediaStore();
+                            //Just because we have a media URI doesn't mean we have a real file, we need to make it
+                            uri = Uri.fromFile(new File(FileHelper.getRealPath(inputUri, this.cordova)));
                         } else {
-                            uri = getUriFromMediaStore();
+                            uri = Uri.fromFile(new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), System.currentTimeMillis() + ".jpg"));
                         }
 
                         if (uri == null) {
@@ -444,7 +446,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                                     ExifHelper exif = new ExifHelper();
                                     try {
                                         if (this.encodingType == JPEG) {
-                                            exif.createInFile(resizePath);
+                                            exif.createInFile(FileHelper.getRealPath(uri, this.cordova));
                                             exif.readExifData();
                                             rotate = exif.getOrientation();
                                         }
@@ -458,7 +460,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
 
                                     // Restore exif data to file
                                     if (this.encodingType == JPEG) {
-                                        exif.createOutFile(FileHelper.getRealPath(uri, this.cordova));
+                                        exif.createOutFile(resizePath);
                                         exif.writeExifData();
                                     }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-android/framework/src/org/apache/cordova/Device.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/Device.java b/lib/cordova-android/framework/src/org/apache/cordova/Device.java
index ad399f0..0f828a1 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/Device.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/Device.java
@@ -38,7 +38,7 @@ import android.telephony.TelephonyManager;
 public class Device extends CordovaPlugin {
     public static final String TAG = "Device";
 
-    public static String cordovaVersion = "2.6.0rc1";              // Cordova version
+    public static String cordovaVersion = "2.6.0";              // Cordova version
     public static String platform = "Android";                  // Device OS
     public static String uuid;                                  // Device UUID
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java b/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
index 48e27c6..0d5d496 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
@@ -151,6 +151,21 @@ public class InAppBrowser extends CordovaPlugin {
                 pluginResult.setKeepCallback(false);
                 this.callbackContext.sendPluginResult(pluginResult);
             }
+            else if (action.equals("injectScriptCode")) {
+                String source = args.getString(0);
+
+                org.json.JSONArray jsonEsc = new org.json.JSONArray();
+                jsonEsc.put(source);
+                String jsonRepr = jsonEsc.toString();
+                String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
+                String scriptEnclosure = "(function(d){var c=d.createElement('script');c.type='text/javascript';c.innerText="
+                                       + jsonSourceString
+                                       + ";d.getElementsByTagName('head')[0].appendChild(c);})(document)";
+                this.inAppWebView.loadUrl("javascript:" + scriptEnclosure);
+
+                PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
+                this.callbackContext.sendPluginResult(pluginResult);
+            }
             else {
                 status = PluginResult.Status.INVALID_ACTION;
             }
@@ -445,7 +460,7 @@ public class InAppBrowser extends CordovaPlugin {
                 
                 //Toggle whether this is enabled or not!
                 Bundle appSettings = cordova.getActivity().getIntent().getExtras();
-                boolean enableDatabase = appSettings.getBoolean("InAppBrowserStorageEnabled", true);
+                boolean enableDatabase = appSettings == null ? true : appSettings.getBoolean("InAppBrowserStorageEnabled", true);
                 if(enableDatabase)
                 {
                     String databasePath = cordova.getActivity().getApplicationContext().getDir("inAppBrowserDB", Context.MODE_PRIVATE).getPath();

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java b/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
index 337ef12..774b21c 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/PluginManager.java
@@ -30,6 +30,7 @@ import org.xmlpull.v1.XmlPullParserException;
 import android.content.Intent;
 import android.content.res.XmlResourceParser;
 
+import android.util.Log;
 import android.webkit.WebResourceResponse;
 
 /**
@@ -213,6 +214,7 @@ public class PluginManager {
     public boolean exec(String service, String action, String callbackId, String rawArgs) {
         CordovaPlugin plugin = this.getPlugin(service);
         if (plugin == null) {
+            Log.d(TAG, "exec() call to unknown plugin: " + service);
             PluginResult cr = new PluginResult(PluginResult.Status.CLASS_NOT_FOUND_EXCEPTION);
             app.sendPluginResult(cr, callbackId);
             return true;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-android/test/res/xml/cordova.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-android/test/res/xml/cordova.xml b/lib/cordova-android/test/res/xml/cordova.xml
deleted file mode 100755
index 4aebda4..0000000
--- a/lib/cordova-android/test/res/xml/cordova.xml
+++ /dev/null
@@ -1,37 +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.
--->
-<cordova>
-    <!--  
-    access elements control the Android whitelist.  
-    Domains are assumed blocked unless set otherwise
-     -->
-
-    <access origin="http://127.0.0.1*"/> <!-- allow local pages -->
-
-    <!-- <access origin="https://example.com" /> allow any secure requests to example.com -->
-    <!-- <access origin="https://example.com" subdomains="true" /> such as above, but including subdomains, such as www -->
-    <!-- <access origin=".*"/> Allow all domains, suggested development use only -->
-
-    <log level="DEBUG"/>
-    <preference name="useBrowserHistory" value="true" />
-</cordova>
-
-
-

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-android/test/res/xml/plugins.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-android/test/res/xml/plugins.xml b/lib/cordova-android/test/res/xml/plugins.xml
deleted file mode 100644
index 17074ef..0000000
--- a/lib/cordova-android/test/res/xml/plugins.xml
+++ /dev/null
@@ -1,39 +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.
--->
-<plugins>
-    <plugin name="App" value="org.apache.cordova.App"/>
-    <plugin name="Activity" value="org.apache.cordova.test.ActivityPlugin"/>
-    <plugin name="Geolocation" value="org.apache.cordova.GeoBroker"/>
-    <plugin name="Device" value="org.apache.cordova.Device"/>
-    <plugin name="Accelerometer" value="org.apache.cordova.AccelListener"/>
-    <plugin name="Compass" value="org.apache.cordova.CompassListener"/>
-    <plugin name="Media" value="org.apache.cordova.AudioHandler"/>
-    <plugin name="Camera" value="org.apache.cordova.CameraLauncher"/>
-    <plugin name="Contacts" value="org.apache.cordova.ContactManager"/>
-    <plugin name="File" value="org.apache.cordova.FileUtils"/>
-    <plugin name="NetworkStatus" value="org.apache.cordova.NetworkManager"/>
-    <plugin name="Notification" value="org.apache.cordova.Notification"/>
-    <plugin name="Storage" value="org.apache.cordova.Storage"/>
-    <plugin name="Temperature" value="org.apache.cordova.TempListener"/>
-    <plugin name="FileTransfer" value="org.apache.cordova.FileTransfer"/>
-    <plugin name="Capture" value="org.apache.cordova.Capture"/>
-    <plugin name="Battery" value="org.apache.cordova.BatteryListener"/>
-    <plugin name="SplashScreen" value="org.apache.cordova.SplashScreen"/>
-</plugins>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-blackberry/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/VERSION b/lib/cordova-blackberry/VERSION
index 437459c..e70b452 100644
--- a/lib/cordova-blackberry/VERSION
+++ b/lib/cordova-blackberry/VERSION
@@ -1 +1 @@
-2.5.0
+2.6.0

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-blackberry/bin/templates/project/www/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/www/VERSION b/lib/cordova-blackberry/bin/templates/project/www/VERSION
index 437459c..e70b452 100644
--- a/lib/cordova-blackberry/bin/templates/project/www/VERSION
+++ b/lib/cordova-blackberry/bin/templates/project/www/VERSION
@@ -1 +1 @@
-2.5.0
+2.6.0

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-blackberry/bin/templates/project/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/www/index.html b/lib/cordova-blackberry/bin/templates/project/www/index.html
index 6b53abc..4d39cf3 100644
--- a/lib/cordova-blackberry/bin/templates/project/www/index.html
+++ b/lib/cordova-blackberry/bin/templates/project/www/index.html
@@ -33,7 +33,7 @@
                 <p class="event received">Device is Ready</p>
             </div>
         </div>
-        <script type="text/javascript" src="cordova-2.5.0.js"></script>
+        <script type="text/javascript" src="cordova-2.6.0.js"></script>
         <script type="text/javascript" src="js/index.js"></script>
         <script type="text/javascript">
             app.initialize();

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java
index 3bb4824..af39a49 100644
--- a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java
@@ -54,7 +54,7 @@ public final class Device extends Plugin {
 				JSONObject device = new JSONObject();
 				device.put( FIELD_PLATFORM, "BlackBerry");
 				device.put( FIELD_UUID, new Integer( DeviceInfo.getDeviceId()) );
-				device.put( FIELD_CORDOVA, "2.5.0" );
+				device.put( FIELD_CORDOVA, "2.6.0" );
 				device.put( FIELD_MODEL, new String(DeviceInfo.getDeviceName()) );
 				device.put( FIELD_NAME, new String(DeviceInfo.getDeviceName()) );
 				device.put( FIELD_VERSION, new String(DeviceInfo.getSoftwareVersion()) );

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/file/FileManager.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/file/FileManager.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/file/FileManager.java
index e0c3556..55ea436 100644
--- a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/file/FileManager.java
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/file/FileManager.java
@@ -96,7 +96,6 @@ public class FileManager extends Plugin {
      * @return A PluginResult object with a status and message.
      */
     public PluginResult execute(String action, JSONArray args, String callbackId) {
-
         // perform specified action
         if (ACTION_READ_AS_TEXT.equals(action)) {
             // get file path
@@ -547,11 +546,11 @@ public class FileManager extends Plugin {
     protected static PluginResult resolveFileSystemURI(String uri) {
         PluginResult result = null;
         Entry entry = null;
-
         try {
             entry = getEntryFromURI(uri);
         }
         catch (IllegalArgumentException e) {
+            Logger.log(e.toString());
             return new PluginResult(
                     PluginResult.Status.JSON_EXCEPTION,
                     ENCODING_ERR);
@@ -565,6 +564,7 @@ public class FileManager extends Plugin {
             result = new PluginResult(PluginResult.Status.OK,
                     entry.toJSONObject());
         }
+
         return result;
     }
 
@@ -889,6 +889,13 @@ public class FileManager extends Plugin {
             throw new IllegalArgumentException("Invalid URI.");
         }
 
+        //check for query string
+        int queryIndex = filePath.indexOf('?');
+        if (queryIndex > 0) {
+            path = filePath.substring(0, queryIndex); // discard the query string
+            Logger.log(FileManager.class.getName() + ": found query string when resolving URI = " + filePath.substring(queryIndex));
+        }
+
         // create a file system entry
         Entry entry = null;
         if (path.startsWith(FileUtils.LOCAL_PROTOCOL)) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-blackberry/javascript/cordova.blackberry.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/javascript/cordova.blackberry.js b/lib/cordova-blackberry/javascript/cordova.blackberry.js
index fbe61f5..86b9e8b 100644
--- a/lib/cordova-blackberry/javascript/cordova.blackberry.js
+++ b/lib/cordova-blackberry/javascript/cordova.blackberry.js
@@ -1,8 +1,8 @@
 // Platform: blackberry
 
-// commit bbf1562d4934b1331ffb263424b6ae054cedeb71
+// commit 125dca530923a44a8f44f68f5e1970cbdd4e7faf
 
-// File generated at :: Fri Mar 22 2013 14:49:45 GMT-0700 (PDT)
+// File generated at :: Wed Apr 03 2013 15:26:44 GMT-0700 (PDT)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -5361,7 +5361,7 @@ module.exports = {
                     model: "PlayBook",
                     name: "PlayBook", // deprecated: please use device.model
                     uuid: info.uuid,
-                    cordova: "2.5.0"
+                    cordova: "2.6.0"
                 });
             }),
             request = new blackberry.transport.RemoteFunctionCall("org/apache/cordova/getDeviceInfo");
@@ -9290,7 +9290,7 @@ module.exports = {
             model: "Dev Alpha",
             name: "Dev Alpha", // deprecated: please use device.model
             uuid: blackberry.identity.uuid,
-            cordova: "2.5.0"
+            cordova: "2.6.0"
         });
 
         return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "Device info returned" };
@@ -10824,27 +10824,32 @@ document.addEventListener("DOMContentLoaded", function () {
     }
 
     // Try to XHR the cordova_plugins.json file asynchronously.
-    var xhr = new context.XMLHttpRequest();
-    xhr.onreadystatechange = function() {
-        if (this.readyState != 4) { // not DONE
-            return;
-        }
+    try { // we commented we were going to try, so let us actually try and catch 
+        var xhr = new context.XMLHttpRequest();
+        xhr.onreadystatechange = function() {
+            if (this.readyState != 4) { // not DONE
+                return;
+            }
 
-        // If the response is a JSON string which composes an array, call handlePluginsObject.
-        // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
-        if (this.status == 200) {
-            var obj = JSON.parse(this.responseText);
-            if (obj && obj instanceof Array && obj.length > 0) {
-                handlePluginsObject(obj);
+            // If the response is a JSON string which composes an array, call handlePluginsObject.
+            // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
+            if (this.status == 200) {
+                var obj = JSON.parse(this.responseText);
+                if (obj && obj instanceof Array && obj.length > 0) {
+                    handlePluginsObject(obj);
+                } else {
+                    finishPluginLoading();
+                }
             } else {
                 finishPluginLoading();
             }
-        } else {
-            finishPluginLoading();
-        }
-    };
-    xhr.open('GET', 'cordova_plugins.json', true); // Async
-    xhr.send();
+        };
+        xhr.open('GET', 'cordova_plugins.json', true); // Async
+        xhr.send();
+    }
+    catch(err) {
+        finishPluginLoading();
+    }
 }(window));
 
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m b/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m
index ab1154e..823fde9 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m
@@ -85,12 +85,6 @@ static NSSet* org_apache_cordova_validArrowDirections;
         return;
     }
 
-    NSNumber* cameraDirection = [arguments objectAtIndex:11];
-    UIImagePickerControllerCameraDevice cameraDevice = UIImagePickerControllerCameraDeviceRear; // default
-    if (cameraDirection != nil) {
-        cameraDevice = (UIImagePickerControllerSourceType)[cameraDirection intValue];
-    }
-
     bool allowEdit = [[arguments objectAtIndex:7] boolValue];
     NSNumber* targetWidth = [arguments objectAtIndex:3];
     NSNumber* targetHeight = [arguments objectAtIndex:4];
@@ -114,7 +108,6 @@ static NSSet* org_apache_cordova_validArrowDirections;
 
     cameraPicker.delegate = self;
     cameraPicker.sourceType = sourceType;
-    cameraPicker.cameraDevice = cameraDevice;
     cameraPicker.allowsEditing = allowEdit; // THIS IS ALL IT TAKES FOR CROPPING - jm
     cameraPicker.callbackId = callbackId;
     cameraPicker.targetSize = targetSize;
@@ -132,18 +125,22 @@ static NSSet* org_apache_cordova_validArrowDirections;
     cameraPicker.returnType = ([arguments objectAtIndex:1]) ? [[arguments objectAtIndex:1] intValue] : DestinationTypeFileUri;
 
     if (sourceType == UIImagePickerControllerSourceTypeCamera) {
-        // we only allow taking pictures (no video) in this api
+        // We only allow taking pictures (no video) in this API.
         cameraPicker.mediaTypes = [NSArray arrayWithObjects:(NSString*)kUTTypeImage, nil];
+
+        // We can only set the camera device if we're actually using the camera.
+        NSNumber* cameraDirection = [command argumentAtIndex:11 withDefault:[NSNumber numberWithInteger:UIImagePickerControllerCameraDeviceRear]];
+        cameraPicker.cameraDevice = (UIImagePickerControllerCameraDevice)[cameraDirection intValue];
     } else if (mediaType == MediaTypeAll) {
         cameraPicker.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:sourceType];
     } else {
-        NSArray* mediaArray = [NSArray arrayWithObjects:(NSString*)(mediaType == MediaTypeVideo ? kUTTypeMovie:kUTTypeImage), nil];
+        NSArray* mediaArray = [NSArray arrayWithObjects:(NSString*)(mediaType == MediaTypeVideo ? kUTTypeMovie : kUTTypeImage), nil];
         cameraPicker.mediaTypes = mediaArray;
     }
 
     if ([self popoverSupported] && (sourceType != UIImagePickerControllerSourceTypeCamera)) {
         if (cameraPicker.popoverController == nil) {
-            cameraPicker.popoverController = [[NSClassFromString (@"UIPopoverController")alloc] initWithContentViewController:cameraPicker];
+            cameraPicker.popoverController = [[NSClassFromString(@"UIPopoverController")alloc] initWithContentViewController:cameraPicker];
         }
         NSDictionary* options = [command.arguments objectAtIndex:10 withDefault:nil];
         [self displayPopover:options];
@@ -299,55 +296,17 @@ static NSSet* org_apache_cordova_validArrowDirections;
                 data = UIImagePNGRepresentation(scaledImage == nil ? image : scaledImage);
             } else {
                 data = UIImageJPEGRepresentation(scaledImage == nil ? image : scaledImage, cameraPicker.quality / 100.0f);
-                
-                CDVJpegHeaderWriter * exifWriter = [[CDVJpegHeaderWriter alloc] init];
-                
-                NSString * headerstring = [exifWriter createExifAPP1: [info objectForKey:@"UIImagePickerControllerMediaMetadata"]];
-                NSMutableData * exifdata = [NSMutableData dataWithCapacity: [headerstring length]/2];
-                int idx;
-                for (idx = 0; idx+1 < [headerstring length]; idx+=2) {
-                    NSRange range = NSMakeRange(idx, 2);
-                    NSString* hexStr = [headerstring substringWithRange:range];
-                    NSScanner* scanner = [NSScanner scannerWithString:hexStr];
-                    unsigned int intValue;
-                    [scanner scanHexInt:&intValue];
-                    [exifdata appendBytes:&intValue length:1];
-                }
-               
-                NSMutableData * ddata = [NSMutableData dataWithCapacity: [data length]];
-                NSMakeRange(0,4);
-                int loc = 0;
-                bool done = false;
-                // read the jpeg data until we encounter the app1==0xFFE1 marker
-                while (loc+1 < [data length]) {
-                    NSData * blag = [data subdataWithRange: NSMakeRange(loc,2)];
-                    if( [[blag description] isEqualToString : @"<ffe1>"]) {
-                        // read the APP1 block size bits
-                        NSString * the = [exifWriter hexStringFromData:[data subdataWithRange: NSMakeRange(loc+2,2)]];
-                        NSNumber * app1width = [exifWriter numericFromHexString:the];
-                        //consume the original app1 block
-                        [ddata appendData:exifdata];
-                        // advance our loc marker past app1
-                        loc += [app1width intValue] + 2;
-                        done = true;
-                    } else {
-                        if(!done) {
-                            [ddata appendData:blag];
-                            loc += 2;
-                        } else {
-                            break;
-                        }
-                    }
-                }
-                // copy the remaining data
-                [ddata appendData:[data subdataWithRange: NSMakeRange(loc,[data length]-loc)]];
-                data = ddata;
+
+                /* splice loc */
+                CDVJpegHeaderWriter* exifWriter = [[CDVJpegHeaderWriter alloc] init];
+                NSString* headerstring = [exifWriter createExifAPP1:[info objectForKey:@"UIImagePickerControllerMediaMetadata"]];
+                data = [exifWriter spliceExifBlockIntoJpeg:data withExifBlock:headerstring];
             }
 
             if (cameraPicker.returnType == DestinationTypeFileUri) {
                 // write to temp directory and return URI
                 // get the temp directory path
-                NSString* docsPath = [NSTemporaryDirectory ()stringByStandardizingPath];
+                NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath];
                 NSError* err = nil;
                 NSFileManager* fileMgr = [[NSFileManager alloc] init]; // recommended by apple (vs [NSFileManager defaultManager]) to be threadsafe
                 // generate unique file name
@@ -472,7 +431,7 @@ static NSSet* org_apache_cordova_validArrowDirections;
             rotation_radians = 0.0;
             break;
 
-        case UIImageOrientationDown :
+        case UIImageOrientationDown:
             rotation_radians = M_PI; // don't be scared of radians, if you're reading this, you're good at math
             break;
 
@@ -571,7 +530,7 @@ static NSSet* org_apache_cordova_validArrowDirections;
     // first parameter an image
     [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
     [postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"upload\"; filename=\"%@\"\r\n", filename] dataUsingEncoding:NSUTF8StringEncoding]];
-    [postBody appendData:[@"Content-Type: image/png\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
+    [postBody appendData:[@"Content-Type: image/png\r\n\r\n" dataUsingEncoding : NSUTF8StringEncoding]];
     [postBody appendData:imageData];
 
     //	// second parameter information

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.h b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.h
index 02fe91f..3b43ef0 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.h
@@ -24,6 +24,8 @@
     NSDictionary * IFD0TagFormatDict;
 }
 
+- (NSData*) spliceExifBlockIntoJpeg: (NSData*) jpegdata
+                      withExifBlock: (NSString*) exifstr;
 - (NSString*) createExifAPP1 : (NSDictionary*) datadict;
 - (NSString*) formattedHexStringFromDecimalNumber: (NSNumber*) numb 
                                        withPlaces: (NSNumber*) width;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m
index 7b59d11..90c96d2 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m
@@ -45,7 +45,7 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
                         TAGINF(@"011a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"XResolution",
                         TAGINF(@"011b", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"YResolution",
                         // currently supplied outside of Exif data block by UIImagePickerControllerMediaMetadata, this is set manually in CDVCamera.m
-                        TAGINF(@"0112", [NSNumber numberWithInt:EDT_USHORT], @1), @"Orientation",
+    /*                    TAGINF(@"0112", [NSNumber numberWithInt:EDT_USHORT], @1), @"Orientation",
                        
                         // rest of the tags are supported by exif spec, but are not specified by UIImagePickerControllerMediaMedadata
                         // should camera hardware supply these values in future versions, or if they can be derived, ImageHeaderWriter will include them gracefully
@@ -58,43 +58,89 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
                         TAGINF(@"8298", [NSNumber numberWithInt:EDT_URATIONAL], @0), @"Copyright",
                          
                         // offset to exif subifd, we determine this dynamically based on the size of the main exif IFD
-                        TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1), @"ExifOffset",
+                        TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1), @"ExifOffset",*/
                         nil];
 
+
     // supported tages for exif subIFD
     SubIFDTagFormatDict = [[NSDictionary alloc] initWithObjectsAndKeys:
-                          // TAGINF(@"9000", [NSNumber numberWithInt:], @), @"ExifVersion",
-                           // TAGINF(@"9202",[NSNumber numberWithInt:EDT_URATIONAL],@1), @"ApertureValue",
-                           // TAGINF(@"9203",[NSNumber numberWithInt:EDT_SRATIONAL],@1), @"BrightnessValue",
+                           //TAGINF(@"9000", [NSNumber numberWithInt:], @), @"ExifVersion",
+                           //TAGINF(@"9202",[NSNumber numberWithInt:EDT_URATIONAL],@1), @"ApertureValue",
+                           //TAGINF(@"9203",[NSNumber numberWithInt:EDT_SRATIONAL],@1), @"BrightnessValue",
                            TAGINF(@"a001",[NSNumber numberWithInt:EDT_USHORT],@1), @"ColorSpace",
                            TAGINF(@"9004",[NSNumber numberWithInt:EDT_ASCII_STRING],@20), @"DateTimeDigitized",
                            TAGINF(@"9003",[NSNumber numberWithInt:EDT_ASCII_STRING],@20), @"DateTimeOriginal",
                            TAGINF(@"a402", [NSNumber numberWithInt:EDT_USHORT], @1), @"ExposureMode",
                            TAGINF(@"8822", [NSNumber numberWithInt:EDT_USHORT], @1), @"ExposureProgram",
-                           TAGINF(@"829a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"ExposureTime",
-                           TAGINF(@"829d", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"FNumber",
+                           //TAGINF(@"829a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"ExposureTime",
+                           //TAGINF(@"829d", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"FNumber",
                            TAGINF(@"9209", [NSNumber numberWithInt:EDT_USHORT], @1), @"Flash",
                            // FocalLengthIn35mmFilm
                            TAGINF(@"a405", [NSNumber numberWithInt:EDT_USHORT], @1), @"FocalLenIn35mmFilm",
-                           TAGINF(@"920a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"FocalLength",
-
+                           //TAGINF(@"920a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"FocalLength",
                            //TAGINF(@"8827", [NSNumber numberWithInt:EDT_USHORT], @2), @"ISOSpeedRatings",
-
-                           TAGINF(@"9207",[NSNumber numberWithInt:EDT_USHORT],@1), @"MeteringMode",
+                           TAGINF(@"9207", [NSNumber numberWithInt:EDT_USHORT],@1), @"MeteringMode",
                            // specific to compressed data
                            TAGINF(@"a002", [NSNumber numberWithInt:EDT_ULONG],@1), @"PixelXDimension",
                            TAGINF(@"a003", [NSNumber numberWithInt:EDT_ULONG],@1), @"PixelYDimension",
                            // data type undefined, but this is a DSC camera, so value is always 1, treat as ushort
                            TAGINF(@"a301", [NSNumber numberWithInt:EDT_USHORT],@1), @"SceneType",
                            TAGINF(@"a217",[NSNumber numberWithInt:EDT_USHORT],@1), @"SensingMethod",
-                    // TAGINF(@"9201", [NSNumber numberWithInt:EDT_SRATIONAL], @1), @"ShutterSpeedValue",
+                           //TAGINF(@"9201", [NSNumber numberWithInt:EDT_SRATIONAL], @1), @"ShutterSpeedValue",
                            // specifies location of main subject in scene (x,y,wdith,height) expressed before rotation processing
-                           // TAGINF(@"9214", [NSNumber numberWithInt:EDT_USHORT], @4), @"SubjectArea",
+                           //TAGINF(@"9214", [NSNumber numberWithInt:EDT_USHORT], @4), @"SubjectArea",
                            TAGINF(@"a403", [NSNumber numberWithInt:EDT_USHORT], @1), @"WhiteBalance",
-                      nil];
+                           nil];
     return self;
 }
 
+- (NSData*) spliceExifBlockIntoJpeg: (NSData*) jpegdata withExifBlock: (NSString*) exifstr {
+    
+    CDVJpegHeaderWriter * exifWriter = [[CDVJpegHeaderWriter alloc] init];
+    
+    NSMutableData * exifdata = [NSMutableData dataWithCapacity: [exifstr length]/2];
+    int idx;
+    for (idx = 0; idx+1 < [exifstr length]; idx+=2) {
+        NSRange range = NSMakeRange(idx, 2);
+        NSString* hexStr = [exifstr substringWithRange:range];
+        NSScanner* scanner = [NSScanner scannerWithString:hexStr];
+        unsigned int intValue;
+        [scanner scanHexInt:&intValue];
+        [exifdata appendBytes:&intValue length:1];
+    }
+    
+    NSMutableData * ddata = [NSMutableData dataWithCapacity: [jpegdata length]];
+    NSMakeRange(0,4);
+    int loc = 0;
+    bool done = false;
+    // read the jpeg data until we encounter the app1==0xFFE1 marker
+    while (loc+1 < [jpegdata length]) {
+        NSData * blag = [jpegdata subdataWithRange: NSMakeRange(loc,2)];
+        if( [[blag description] isEqualToString : @"<ffe1>"]) {
+            // read the APP1 block size bits
+            NSString * the = [exifWriter hexStringFromData:[jpegdata subdataWithRange: NSMakeRange(loc+2,2)]];
+            NSNumber * app1width = [exifWriter numericFromHexString:the];
+            //consume the original app1 block
+            [ddata appendData:exifdata];
+            // advance our loc marker past app1
+            loc += [app1width intValue] + 2;
+            done = true;
+        } else {
+            if(!done) {
+                [ddata appendData:blag];
+                loc += 2;
+            } else {
+                break;
+            }
+        }
+    }
+    // copy the remaining data
+    [ddata appendData:[jpegdata subdataWithRange: NSMakeRange(loc,[jpegdata length]-loc)]];
+    return ddata;
+}
+
+
+
 /**
  * Create the Exif data block as a hex string
  *   jpeg uses Application Markers (APP's) as markers for application data
@@ -127,11 +173,15 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
 
     //data labeled as EXIF in UIImagePickerControllerMediaMetaData is part of the EXIF Sub IFD portion of APP1
     subExifIFD = [self createExifIFDFromDict: [datadict objectForKey:@"{Exif}"] withFormatDict: SubIFDTagFormatDict isIFD0:NO];
-
+    /*
+    NSLog(@"SUB EXIF IFD %@  WITH SIZE: %d",exifIFD,[exifIFD length]);
+    
+    NSLog(@"SUB EXIF IFD %@  WITH SIZE: %d",subExifIFD,[subExifIFD length]);
+    */
     // construct the complete app1 data block
     app1 = [[NSMutableString alloc] initWithFormat: @"%@%04x%@%@%@%@%@",
             app1marker,
-            16+[exifIFD length]/2+[subExifIFD length]/2/*16+[exifIFD length]/2*/,
+            16 + ([exifIFD length]/2) + ([subExifIFD length]/2) /*16+[exifIFD length]/2*/,
             exifmarker,
             tiffheader,
             ifd0offset,
@@ -147,7 +197,7 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
     NSArray * knownkeys = [formatdict  allKeys]; // only keys in knowkeys are considered for entry in this IFD
     NSMutableArray * ifdblock = [[NSMutableArray alloc] initWithCapacity: [datadict count]]; // all ifd entries
     NSMutableArray * ifddatablock = [[NSMutableArray alloc] initWithCapacity: [datadict count]]; // data block entries
-    ifd0flag = NO; // ifd0 requires a special flag and has offset to next ifd appended to end
+ //   ifd0flag = NO; // ifd0 requires a special flag and has offset to next ifd appended to end
     
     // iterate through known provided data keys
     for (int i = 0; i < [datakeys count]; i++) {
@@ -156,7 +206,7 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
         if ([knownkeys indexOfObject: key] != NSNotFound) {
             // create new IFD entry
             NSString * entry = [self  createIFDElement: key
-                                      withFormatDict: formatdict
+                                            withFormat: [formatdict objectForKey:key]
                                       withElementData: [datadict objectForKey:key]];
             // create the IFD entry's data block
             NSString * data = [self createIFDElementDataWithFormat: [formatdict objectForKey:key]
@@ -202,7 +252,8 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
     // calculate IFD0 terminal offset tags, currently ExifSubIFD
     int entrycount = [ifdblock count];
     if (ifd0flag) {
-        NSNumber * offset = [NSNumber numberWithInt:[exifstr length] / 2 + [dbstr length] / 2 ];
+        // 18 accounts for 8769's width + offset to next ifd, 8 accounts for start of header
+        NSNumber * offset = [NSNumber numberWithInt:[exifstr length] / 2 + [dbstr length] / 2 + 18+8];
         
         [self appendExifOffsetTagTo: exifstr
                         withOffset : offset];
@@ -216,18 +267,18 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
 }
 
 // Creates an exif formatted exif information file directory entry
-- (NSString*) createIFDElement: (NSString*) elementName withFormatDict : (NSDictionary*) formatdict withElementData : (NSString*) data  {
-    NSArray * fielddata = [formatdict objectForKey: elementName];// format data of desired field
-    if (fielddata) {
+- (NSString*) createIFDElement: (NSString*) elementName withFormat: (NSArray*) formtemplate withElementData: (NSString*) data  {
+    //NSArray * fielddata = [formatdict objectForKey: elementName];// format data of desired field
+    if (formtemplate) {
         // format string @"%@%@%@%@", tag number, data format, components, value
-        NSNumber * dataformat = [fielddata objectAtIndex:1];
-        NSNumber * components = [fielddata objectAtIndex:2];
+        NSNumber * dataformat = [formtemplate objectAtIndex:1];
+        NSNumber * components = [formtemplate objectAtIndex:2];
         if([components intValue] == 0) {
             components = [NSNumber numberWithInt: [data length] * DataTypeToWidth[[dataformat intValue]-1]];            
         }
 
         return [[NSString alloc] initWithFormat: @"%@%@%08x",
-                                                [fielddata objectAtIndex:0], // the field code
+                                                [formtemplate objectAtIndex:0], // the field code
                                                 [self formatNumberWithLeadingZeroes: dataformat withPlaces: @4], // the data type code
                                                 [components intValue]]; // number of components
     }
@@ -243,7 +294,7 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
     NSArray * format = TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1);
     
     NSString * entry = [self  createIFDElement: @"ExifOffset"
-                                withFormatDict: IFD0TagFormatDict
+                                withFormat: format
                                withElementData: [offset stringValue]];
     
     NSString * data = [self createIFDElementDataWithFormat: format
@@ -275,7 +326,7 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
         case EDT_USHORT:
             return [[NSString alloc] initWithFormat : @"%@%@",
                     [self formattedHexStringFromDecimalNumber: [NSNumber numberWithInt: [data intValue]] withPlaces: @4],
-                    @"00000000"];
+                    @"0000"];
         case EDT_ULONG:
             tmp = [NSNumber numberWithUnsignedLong:[data intValue]];
             return [NSString stringWithFormat : @"%@",
@@ -290,7 +341,6 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
         case EDT_UNDEFINED:
             break;     // 8 bits
         case EDT_SSHORT:
-            
             break;
         case EDT_SLONG:
             break;          // 32bit signed integer (2's complement)

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m b/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m
index efe3eaa..45889a0 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m
@@ -87,7 +87,12 @@
     // Set the frame & image later.
     _imageView = [[UIImageView alloc] init];
     [parentView addSubview:_imageView];
-    [parentView addSubview:_activityView];
+
+    id showSplashScreenSpinnerValue = [self.commandDelegate.settings objectForKey:@"ShowSplashScreenSpinner"];
+    // backwards compatibility - if key is missing, default to true
+    if ((showSplashScreenSpinnerValue == nil) || [showSplashScreenSpinnerValue boolValue]) {
+        [parentView addSubview:_activityView];
+    }
 
     // Frame is required when launching in portrait mode.
     // Bounds for landscape since it captures the rotation.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-ios/CordovaLib/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/VERSION b/lib/cordova-ios/CordovaLib/VERSION
index f47de85..e70b452 100644
--- a/lib/cordova-ios/CordovaLib/VERSION
+++ b/lib/cordova-ios/CordovaLib/VERSION
@@ -1 +1 @@
-2.6.0rc1
+2.6.0

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-ios/CordovaLib/cordova.ios.js
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/cordova.ios.js b/lib/cordova-ios/CordovaLib/cordova.ios.js
index 8ed1706..4df7891 100644
--- a/lib/cordova-ios/CordovaLib/cordova.ios.js
+++ b/lib/cordova-ios/CordovaLib/cordova.ios.js
@@ -1,8 +1,8 @@
 // Platform: ios
 
-// commit 47593b2bc1dba9bf46545b1da24577f937966e12
+// commit 125dca530923a44a8f44f68f5e1970cbdd4e7faf
 
-// File generated at :: Thu Mar 21 2013 15:44:06 GMT-0700 (PDT)
+// File generated at :: Thu Apr 04 2013 10:21:55 GMT-0700 (PDT)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -6400,27 +6400,32 @@ window.cordova = require('cordova');
     }
 
     // Try to XHR the cordova_plugins.json file asynchronously.
-    var xhr = new context.XMLHttpRequest();
-    xhr.onreadystatechange = function() {
-        if (this.readyState != 4) { // not DONE
-            return;
-        }
+    try { // we commented we were going to try, so let us actually try and catch 
+        var xhr = new context.XMLHttpRequest();
+        xhr.onreadystatechange = function() {
+            if (this.readyState != 4) { // not DONE
+                return;
+            }
 
-        // If the response is a JSON string which composes an array, call handlePluginsObject.
-        // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
-        if (this.status == 200) {
-            var obj = JSON.parse(this.responseText);
-            if (obj && obj instanceof Array && obj.length > 0) {
-                handlePluginsObject(obj);
+            // If the response is a JSON string which composes an array, call handlePluginsObject.
+            // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
+            if (this.status == 200) {
+                var obj = JSON.parse(this.responseText);
+                if (obj && obj instanceof Array && obj.length > 0) {
+                    handlePluginsObject(obj);
+                } else {
+                    finishPluginLoading();
+                }
             } else {
                 finishPluginLoading();
             }
-        } else {
-            finishPluginLoading();
-        }
-    };
-    xhr.open('GET', 'cordova_plugins.json', true); // Async
-    xhr.send();
+        };
+        xhr.open('GET', 'cordova_plugins.json', true); // Async
+        xhr.send();
+    }
+    catch(err) {
+        finishPluginLoading();
+    }
 }(window));
 
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-ios/RELEASENOTES.md
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/RELEASENOTES.md b/lib/cordova-ios/RELEASENOTES.md
index e83c647..aa501b0 100644
--- a/lib/cordova-ios/RELEASENOTES.md
+++ b/lib/cordova-ios/RELEASENOTES.md
@@ -24,6 +24,10 @@
 
 ### 2.6.0 (20130401) ###
 
+* [CB-2732] Only set camera device when allowed.
+* [CB-2848] ShowSplashScreenSpinner not used
+* [CB-2790] added splice function to header writer: accepts jpeg as NSData, 
+* [CB-2790] removed old splice code, replaced with JpegHeaderWriter api call
 * [CB-1547] Scope notifications to WebViews
 * [CB-2461] Distinguish sub-frame from top-level loads in InAppBrowser.
 * [CB-2523] Add setting to shrink webview when keyboard pops up

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/56b42470/lib/cordova-ios/bin/README.md
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/README.md b/lib/cordova-ios/bin/README.md
deleted file mode 100644
index d5ffc63..0000000
--- a/lib/cordova-ios/bin/README.md
+++ /dev/null
@@ -1,29 +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.
-#
--->
-
-Updating the template project
------------------------------
-
-1. Generate the tagged JavaScript file from the **cordova-js** repo
-2. Delete the **cordova-X.X.X.js** file in **templates/project/www**
-3. Copy the file from (1) into **templates/project/www**
-4. Rename the file in (3) to **cordova-X.X.X.js** where X.X.X is the current Cordova version
-5. Update the **&lt;script&gt;** tag reference for the **templates/project/www/index.html** file to point to (4)


[22/43] 2.6.0rc1 used for libs now. Bumped npm version to 2.6.0. added androids local.properties to gitignore.

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/FileUtils.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/FileUtils.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/FileUtils.java
index 2655ef6..20ef492 100644
--- a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/FileUtils.java
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/util/FileUtils.java
@@ -23,6 +23,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.Enumeration;
+import java.util.Random;
 
 import javax.microedition.io.Connector;
 import javax.microedition.io.file.FileConnection;
@@ -35,6 +36,7 @@ import net.rim.device.api.io.FileNotFoundException;
 import net.rim.device.api.io.IOUtilities;
 import net.rim.device.api.io.MIMETypeAssociations;
 import net.rim.device.api.system.Application;
+import net.rim.device.api.system.ControlledAccessException;
 
 /**
  * Contains file utility methods.
@@ -45,7 +47,13 @@ public class FileUtils {
     public static final String LOCAL_PROTOCOL = "local://";
     public static final String FILE_PROTOCOL = "file://";
 
-    private static final String APP_TMP_DIR    = "tmp" + CordovaExtension.getAppID();
+    private static final String APP_TMP_DIR;
+    
+    // init APP_TMP_DIR with a random value
+    static {
+        Random gen = new Random();
+        APP_TMP_DIR = "tmp" + Math.abs(gen.nextInt());
+    }
 
     /**
      * Reads file as byte array.
@@ -226,6 +234,9 @@ public class FileUtils {
                 return;
             }
             fconn.mkdir();
+        } catch (ControlledAccessException e) {
+            Logger.log("ControlledAccessException on dir " + dirPath + ", either directory conflict after reinstall of app, or device is connected via usb, see Cordova Docs File Blackberry Quirks");
+            Logger.log(e.toString());
         }
         finally {
             try {
@@ -237,6 +248,26 @@ public class FileUtils {
     }
 
     /**
+     * Determines the size of a file on the file system. Size always represents number of bytes contained in the file; never pre-allocated but empty space
+     * @return size in bytes of the selected file, or -1 if the file does not exist or is inaccessible
+     */
+    public static long fileSize(String path) throws IOException {
+        FileConnection fconn = null;
+        long fsize = -1;
+        try {
+            fconn = (FileConnection)Connector.open(path);
+            fsize = fconn.fileSize();
+        } catch (IOException e) {
+            Logger.log(FileUtils.class.getName() + " fileSize:  " + path + "not found or inaccessible");
+        } finally {
+            try {
+                if (fconn != null) fconn.close();
+            } catch (IOException ignored) {}
+        }
+       return fsize;
+    }
+
+    /**
      * Copies a file or directory to a new location. If copying a directory, the
      * entire contents of the directory are copied recursively.
      *

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-blackberry/javascript/cordova.blackberry.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/javascript/cordova.blackberry.js b/lib/cordova-blackberry/javascript/cordova.blackberry.js
index 988dd43..fbe61f5 100644
--- a/lib/cordova-blackberry/javascript/cordova.blackberry.js
+++ b/lib/cordova-blackberry/javascript/cordova.blackberry.js
@@ -1,8 +1,8 @@
 // Platform: blackberry
 
-// commit c5437f050947a65045222c6ac9fa70cf71ba334e
+// commit bbf1562d4934b1331ffb263424b6ae054cedeb71
 
-// File generated at :: Wed Feb 27 2013 13:16:46 GMT-0800 (PST)
+// File generated at :: Fri Mar 22 2013 14:49:45 GMT-0700 (PDT)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -725,7 +725,6 @@ channel.createSticky('onCordovaInfoReady');
 channel.createSticky('onCordovaConnectionReady');
 
 // Event to indicate that all automatically loaded JS plugins are loaded and ready.
-// This is used in conjunction with the automatic plugin JS loading CLI prototype.
 channel.createSticky('onPluginsReady');
 
 // Event to indicate that Cordova is ready
@@ -1033,9 +1032,10 @@ cameraExport.getPicture = function(successCallback, errorCallback, options) {
     var correctOrientation = !!options.correctOrientation;
     var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
     var popoverOptions = getValue(options.popoverOptions, null);
+    var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
 
     var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
-                mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions];
+                mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
 
     exec(successCallback, errorCallback, "Camera", "takePicture", args);
     return new CameraPopoverHandle();
@@ -1078,6 +1078,10 @@ module.exports = {
       ARROW_LEFT : 4,
       ARROW_RIGHT : 8,
       ARROW_ANY : 15
+  },
+  Direction:{
+      BACK: 0,
+      FRONT: 1
   }
 };
 
@@ -2269,14 +2273,7 @@ FileReader.prototype.readAsText = function(file, encoding) {
     // Default encoding is UTF-8
     var enc = encoding ? encoding : "UTF-8";
     var me = this;
-    var execArgs = [this._fileName, enc];
-
-    // Maybe add slice parameters.
-    if (file.end < file.size) {
-        execArgs.push(file.start, file.end);
-    } else if (file.start > 0) {
-        execArgs.push(file.start);
-    }
+    var execArgs = [this._fileName, enc, file.start, file.end];
 
     // Read file
     exec(
@@ -2345,14 +2342,7 @@ FileReader.prototype.readAsDataURL = function(file) {
     }
 
     var me = this;
-    var execArgs = [this._fileName];
-
-    // Maybe add slice parameters.
-    if (file.end < file.size) {
-        execArgs.push(file.start, file.end);
-    } else if (file.start > 0) {
-        execArgs.push(file.start);
-    }
+    var execArgs = [this._fileName, file.start, file.end];
 
     // Read file
     exec(
@@ -2415,9 +2405,59 @@ FileReader.prototype.readAsBinaryString = function(file) {
     if (initRead(this, file)) {
         return this._realReader.readAsBinaryString(file);
     }
-    // TODO - Can't return binary data to browser.
-    console.log('method "readAsBinaryString" is not supported at this time.');
-    this.abort();
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsBinaryString", execArgs);
 };
 
 /**
@@ -2429,9 +2469,59 @@ FileReader.prototype.readAsArrayBuffer = function(file) {
     if (initRead(this, file)) {
         return this._realReader.readAsArrayBuffer(file);
     }
-    // TODO - Can't return binary data to browser.
-    console.log('This method is not supported at this time.');
-    this.abort();
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsArrayBuffer", execArgs);
 };
 
 module.exports = FileReader;
@@ -2477,6 +2567,38 @@ function newProgressEvent(result) {
     return pe;
 }
 
+function getBasicAuthHeader(urlString) {
+    var header =  null;
+
+    if (window.btoa) {
+        // parse the url using the Location object
+        var url = document.createElement('a');
+        url.href = urlString;
+
+        var credentials = null;
+        var protocol = url.protocol + "//";
+        var origin = protocol + url.host;
+
+        // check whether there are the username:password credentials in the url
+        if (url.href.indexOf(origin) != 0) { // credentials found
+            var atIndex = url.href.indexOf("@");
+            credentials = url.href.substring(protocol.length, atIndex);
+        }
+
+        if (credentials) {
+            var authHeader = "Authorization";
+            var authHeaderValue = "Basic " + window.btoa(credentials);
+
+            header = {
+                name : authHeader,
+                value : authHeaderValue
+            };
+        }
+    }
+
+    return header;
+}
+
 var idCounter = 0;
 
 /**
@@ -2507,6 +2629,18 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
     var params = null;
     var chunkedMode = true;
     var headers = null;
+
+    var basicAuthHeader = getBasicAuthHeader(server);
+    if (basicAuthHeader) {
+        if (!options) {
+            options = new FileUploadOptions();
+        }
+        if (!options.headers) {
+            options.headers = {};
+        }
+        options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+    }
+
     if (options) {
         fileKey = options.fileKey;
         fileName = options.fileName;
@@ -2548,10 +2682,28 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
  * @param successCallback (Function}  Callback to be invoked when upload has completed
  * @param errorCallback {Function}    Callback to be invoked upon error
  * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+ * @param options {FileDownloadOptions} Optional parameters such as headers
  */
-FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts) {
+FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts, options) {
     argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments);
     var self = this;
+
+    var basicAuthHeader = getBasicAuthHeader(source);
+    if (basicAuthHeader) {
+        if (!options) {
+            options = {};
+        }
+        if (!options.headers) {
+            options.headers = {};
+        }
+        options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+    }
+
+    var headers = null;
+    if (options) {
+        headers = options.headers || null;
+    }
+
     var win = function(result) {
         if (typeof result.lengthComputable != "undefined") {
             if (self.onprogress) {
@@ -2578,7 +2730,7 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
         errorCallback(error);
     };
 
-    exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id]);
+    exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id, headers]);
 };
 
 /**
@@ -2976,6 +3128,7 @@ function InAppBrowser() {
    this.channels = {
         'loadstart': channel.create('loadstart'),
         'loadstop' : channel.create('loadstop'),
+        'loaderror' : channel.create('loaderror'),
         'exit' : channel.create('exit')
    };
 }
@@ -3006,7 +3159,7 @@ module.exports = function(strUrl, strWindowName, strWindowFeatures) {
     var cb = function(eventname) {
        iab._eventHandler(eventname);
     };
-    exec(cb, null, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
+    exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
     return iab;
 };
 
@@ -8682,6 +8835,7 @@ modulemapper.defaults('cordova/plugin/Connection', 'Connection');
 define("cordova/plugin/notification", function(require, exports, module) {
 
 var exec = require('cordova/exec');
+var platform = require('cordova/platform');
 
 /**
  * Provides access to notifications on the device.
@@ -8710,15 +8864,53 @@ module.exports = {
      * @param {String} message              Message to print in the body of the alert
      * @param {Function} resultCallback     The callback that is called when user clicks on a button.
      * @param {String} title                Title of the alert dialog (default: Confirm)
-     * @param {String} buttonLabels         Comma separated list of the labels of the buttons (default: 'OK,Cancel')
+     * @param {Array} buttonLabels          Array of the labels of the buttons (default: ['OK', 'Cancel'])
      */
     confirm: function(message, resultCallback, title, buttonLabels) {
         var _title = (title || "Confirm");
-        var _buttonLabels = (buttonLabels || "OK,Cancel");
+        var _buttonLabels = (buttonLabels || ["OK", "Cancel"]);
+
+        // Strings are deprecated!
+        if (typeof _buttonLabels === 'string') {
+            console.log("Notification.confirm(string, function, string, string) is deprecated.  Use Notification.confirm(string, function, string, array).");
+        }
+
+        // Android and iOS take an array of button label names.
+        // Other platforms take a comma separated list.
+        // For compatibility, we convert to the desired type based on the platform.
+        if (platform.id == "android" || platform.id == "ios") {
+            if (typeof _buttonLabels === 'string') {
+                var buttonLabelString = _buttonLabels;
+                _buttonLabels = buttonLabelString.split(",");
+            }
+        } else {
+            if (Array.isArray(_buttonLabels)) {
+                var buttonLabelArray = _buttonLabels;
+                _buttonLabels = buttonLabelArray.toString();
+            }
+        }
         exec(resultCallback, null, "Notification", "confirm", [message, _title, _buttonLabels]);
     },
 
     /**
+     * Open a native prompt dialog, with a customizable title and button text.
+     * The following results are returned to the result callback:
+     *  buttonIndex     Index number of the button selected.
+     *  input1          The text entered in the prompt dialog box.
+     *
+     * @param {String} message              Dialog message to display (default: "Prompt message")
+     * @param {Function} resultCallback     The callback that is called when user clicks on a button.
+     * @param {String} title                Title of the dialog (default: "Prompt")
+     * @param {Array} buttonLabels          Array of strings for the button labels (default: ["OK","Cancel"])
+     */
+    prompt: function(message, resultCallback, title, buttonLabels) {
+        var _message = (message || "Prompt message");
+        var _title = (title || "Prompt");
+        var _buttonLabels = (buttonLabels || ["OK","Cancel"]);
+        exec(resultCallback, null, "Notification", "prompt", [_message, _title, _buttonLabels]);
+    },
+
+    /**
      * Causes the device to vibrate.
      *
      * @param {Integer} mills       The number of milliseconds to vibrate for.
@@ -10506,15 +10698,6 @@ window.cordova = require('cordova');
     /**
      * Create all cordova objects once page has fully loaded and native side is ready.
      */
-    var joinEvents = [ channel.onDOMContentLoaded, channel.onNativeReady ];
-
-    // If this property is set to something truthy, join on onPluginsReady too.
-    // This property is set by the automatic JS installation prototype in cordova-cli,
-    // and will be removed when the prototype either becomes mainline or is dropped.
-    if (window.__onPluginsLoadedHack) {
-        joinEvents.push(channel.onPluginsReady);
-    }
-
     channel.join(function() {
         var builder = require('cordova/builder'),
             platform = require('cordova/platform');
@@ -10535,7 +10718,7 @@ window.cordova = require('cordova');
             require('cordova').fireDocumentEvent('deviceready');
         }, channel.deviceReadyChannelsArray);
 
-    }, joinEvents);
+    }, [ channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady ]);
 
 }(window));
 
@@ -10565,5 +10748,105 @@ document.addEventListener("DOMContentLoaded", function () {
     }
 });
 
+// file: lib/scripts/plugin_loader.js
+
+// 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.
+(function (context) {
+    // To be populated with the handler by handlePluginsObject.
+    var onScriptLoadingComplete;
+
+    var scriptCounter = 0;
+    function scriptLoadedCallback() {
+        scriptCounter--;
+        if (scriptCounter === 0) {
+            onScriptLoadingComplete && onScriptLoadingComplete();
+        }
+    }
+
+    // Helper function to inject a <script> tag.
+    function injectScript(path) {
+        scriptCounter++;
+        var script = document.createElement("script");
+        script.onload = scriptLoadedCallback;
+        script.src = path;
+        document.head.appendChild(script);
+    }
+
+    // Called when:
+    // * There are plugins defined and all plugins are finished loading.
+    // * There are no plugins to load.
+    function finishPluginLoading() {
+        context.cordova.require('cordova/channel').onPluginsReady.fire();
+    }
+
+    // Handler for the cordova_plugins.json 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 XHR response handler will just call finishPluginLoading().
+    function handlePluginsObject(modules) {
+        // First create the callback for when all plugins are loaded.
+        var mapper = context.cordova.require('cordova/modulemapper');
+        onScriptLoadingComplete = function() {
+            // Loop through all the plugins and then through their clobbers and merges.
+            for (var i = 0; i < modules.length; i++) {
+                var module = modules[i];
+                if (!module) continue;
+
+                if (module.clobbers && module.clobbers.length) {
+                    for (var j = 0; j < module.clobbers.length; j++) {
+                        mapper.clobbers(module.id, module.clobbers[j]);
+                    }
+                }
+
+                if (module.merges && module.merges.length) {
+                    for (var k = 0; k < module.merges.length; k++) {
+                        mapper.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)) {
+                    context.cordova.require(module.id);
+                }
+            }
+
+            finishPluginLoading();
+        };
+
+        // Now inject the scripts.
+        for (var i = 0; i < modules.length; i++) {
+            injectScript(modules[i].file);
+        }
+    }
+
+    // Try to XHR the cordova_plugins.json file asynchronously.
+    var xhr = new context.XMLHttpRequest();
+    xhr.onreadystatechange = function() {
+        if (this.readyState != 4) { // not DONE
+            return;
+        }
+
+        // If the response is a JSON string which composes an array, call handlePluginsObject.
+        // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
+        if (this.status == 200) {
+            var obj = JSON.parse(this.responseText);
+            if (obj && obj instanceof Array && obj.length > 0) {
+                handlePluginsObject(obj);
+            } else {
+                finishPluginLoading();
+            }
+        } else {
+            finishPluginLoading();
+        }
+    };
+    xhr.open('GET', 'cordova_plugins.json', true); // Async
+    xhr.send();
+}(window));
+
+
 
 })();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h b/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
index 33c6799..947ae2d 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
@@ -17,6 +17,8 @@
  under the License.
  */
 
+#define __CORDOVA_IOS__
+
 #define __CORDOVA_0_9_6 906
 #define __CORDOVA_1_0_0 10000
 #define __CORDOVA_1_1_0 10100
@@ -37,6 +39,7 @@
 #define __CORDOVA_2_3_0 20300
 #define __CORDOVA_2_4_0 20400
 #define __CORDOVA_2_5_0 20500
+#define __CORDOVA_2_6_0 20600
 #define __CORDOVA_NA 99999      /* not available */
 
 /*
@@ -47,7 +50,7 @@
  #endif
  */
 #ifndef CORDOVA_VERSION_MIN_REQUIRED
-    #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_2_5_0
+    #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_2_6_0
 #endif
 
 /*
@@ -65,12 +68,20 @@
 
 /* Return the string version of the decimal version */
 #define CDV_VERSION [NSString stringWithFormat:@"%d.%d.%d", \
-        (CORDOVA_VERSION_MIN_REQUIRED / 10000),             \
-        (CORDOVA_VERSION_MIN_REQUIRED % 10000) / 100,       \
-        (CORDOVA_VERSION_MIN_REQUIRED % 10000) % 100]
+    (CORDOVA_VERSION_MIN_REQUIRED / 10000),                 \
+    (CORDOVA_VERSION_MIN_REQUIRED % 10000) / 100,           \
+    (CORDOVA_VERSION_MIN_REQUIRED % 10000) % 100]
 
 #ifdef __clang__
     #define CDV_DEPRECATED(version, msg) __attribute__((deprecated("Deprecated in Cordova " #version ". " msg)))
 #else
     #define CDV_DEPRECATED(version, msg) __attribute__((deprecated()))
 #endif
+
+// Enable this to log all exec() calls.
+#define CDV_ENABLE_EXEC_LOGGING 0
+#if CDV_ENABLE_EXEC_LOGGING
+    #define CDV_EXEC_LOG NSLog
+#else
+    #define CDV_EXEC_LOG(...) do {} while (NO)
+#endif

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVCamera.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCamera.h b/lib/cordova-ios/CordovaLib/Classes/CDVCamera.h
index 204d25f..65eac77 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCamera.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCamera.h
@@ -61,8 +61,8 @@ typedef NSUInteger CDVMediaType;
 // ======================================================================= //
 
 @interface CDVCamera : CDVPlugin <UIImagePickerControllerDelegate,
-    UINavigationControllerDelegate,
-    UIPopoverControllerDelegate>
+                       UINavigationControllerDelegate,
+                       UIPopoverControllerDelegate>
 {}
 
 @property (strong) CDVCameraPicker* pickerController;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m b/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m
index aabe844..ab1154e 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m
@@ -18,6 +18,7 @@
  */
 
 #import "CDVCamera.h"
+#import "CDVJpegHeaderWriter.h"
 #import "NSArray+Comparisons.h"
 #import "NSData+Base64.h"
 #import "NSDictionary+Extensions.h"
@@ -60,6 +61,8 @@ static NSSet* org_apache_cordova_validArrowDirections;
  *  7       allowsEdit
  *  8       correctOrientation
  *  9       saveToPhotoAlbum
+ *  10      popoverOptions
+ *  11      cameraDirection
  */
 - (void)takePicture:(CDVInvokedUrlCommand*)command
 {
@@ -82,6 +85,12 @@ static NSSet* org_apache_cordova_validArrowDirections;
         return;
     }
 
+    NSNumber* cameraDirection = [arguments objectAtIndex:11];
+    UIImagePickerControllerCameraDevice cameraDevice = UIImagePickerControllerCameraDeviceRear; // default
+    if (cameraDirection != nil) {
+        cameraDevice = (UIImagePickerControllerSourceType)[cameraDirection intValue];
+    }
+
     bool allowEdit = [[arguments objectAtIndex:7] boolValue];
     NSNumber* targetWidth = [arguments objectAtIndex:3];
     NSNumber* targetHeight = [arguments objectAtIndex:4];
@@ -105,6 +114,7 @@ static NSSet* org_apache_cordova_validArrowDirections;
 
     cameraPicker.delegate = self;
     cameraPicker.sourceType = sourceType;
+    cameraPicker.cameraDevice = cameraDevice;
     cameraPicker.allowsEditing = allowEdit; // THIS IS ALL IT TAKES FOR CROPPING - jm
     cameraPicker.callbackId = callbackId;
     cameraPicker.targetSize = targetSize;
@@ -289,6 +299,49 @@ static NSSet* org_apache_cordova_validArrowDirections;
                 data = UIImagePNGRepresentation(scaledImage == nil ? image : scaledImage);
             } else {
                 data = UIImageJPEGRepresentation(scaledImage == nil ? image : scaledImage, cameraPicker.quality / 100.0f);
+                
+                CDVJpegHeaderWriter * exifWriter = [[CDVJpegHeaderWriter alloc] init];
+                
+                NSString * headerstring = [exifWriter createExifAPP1: [info objectForKey:@"UIImagePickerControllerMediaMetadata"]];
+                NSMutableData * exifdata = [NSMutableData dataWithCapacity: [headerstring length]/2];
+                int idx;
+                for (idx = 0; idx+1 < [headerstring length]; idx+=2) {
+                    NSRange range = NSMakeRange(idx, 2);
+                    NSString* hexStr = [headerstring substringWithRange:range];
+                    NSScanner* scanner = [NSScanner scannerWithString:hexStr];
+                    unsigned int intValue;
+                    [scanner scanHexInt:&intValue];
+                    [exifdata appendBytes:&intValue length:1];
+                }
+               
+                NSMutableData * ddata = [NSMutableData dataWithCapacity: [data length]];
+                NSMakeRange(0,4);
+                int loc = 0;
+                bool done = false;
+                // read the jpeg data until we encounter the app1==0xFFE1 marker
+                while (loc+1 < [data length]) {
+                    NSData * blag = [data subdataWithRange: NSMakeRange(loc,2)];
+                    if( [[blag description] isEqualToString : @"<ffe1>"]) {
+                        // read the APP1 block size bits
+                        NSString * the = [exifWriter hexStringFromData:[data subdataWithRange: NSMakeRange(loc+2,2)]];
+                        NSNumber * app1width = [exifWriter numericFromHexString:the];
+                        //consume the original app1 block
+                        [ddata appendData:exifdata];
+                        // advance our loc marker past app1
+                        loc += [app1width intValue] + 2;
+                        done = true;
+                    } else {
+                        if(!done) {
+                            [ddata appendData:blag];
+                            loc += 2;
+                        } else {
+                            break;
+                        }
+                    }
+                }
+                // copy the remaining data
+                [ddata appendData:[data subdataWithRange: NSMakeRange(loc,[data length]-loc)]];
+                data = ddata;
             }
 
             if (cameraPicker.returnType == DestinationTypeFileUri) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVCapture.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCapture.m b/lib/cordova-ios/CordovaLib/Classes/CDVCapture.m
index ed9f664..d89e3d3 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCapture.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCapture.m
@@ -169,7 +169,7 @@
     }
 
     // write to temp directory and return URI
-    NSString* docsPath = [NSTemporaryDirectory ()stringByStandardizingPath];  // use file system temporary directory
+    NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath];   // use file system temporary directory
     NSError* err = nil;
     NSFileManager* fileMgr = [[NSFileManager alloc] init];
 
@@ -439,7 +439,7 @@
         if ([command isKindOfClass:[CDVFile class]]) {
             CDVFile* cdvFile = (CDVFile*)command;
             NSString* mimeType = [cdvFile getMimeTypeFromPath:fullPath];
-            [fileDict setObject:(mimeType != nil ? (NSObject*)mimeType:[NSNull null]) forKey:@"type"];
+            [fileDict setObject:(mimeType != nil ? (NSObject*)mimeType : [NSNull null]) forKey:@"type"];
         }
     }
     NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:fullPath error:nil];
@@ -533,7 +533,6 @@
         // delegate to CVDAudioRecorderViewController
         return [self.topViewController supportedInterfaceOrientations];
     }
-
 #endif
 
 @end
@@ -663,7 +662,7 @@
 
     // create file to record to in temporary dir
 
-    NSString* docsPath = [NSTemporaryDirectory ()stringByStandardizingPath];  // use file system temporary directory
+    NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath];   // use file system temporary directory
     NSError* err = nil;
     NSFileManager* fileMgr = [[NSFileManager alloc] init];
 
@@ -701,7 +700,6 @@
         orientation = orientation | (supported & UIInterfaceOrientationMaskPortraitUpsideDown);
         return orientation;
     }
-
 #endif
 
 - (void)viewDidUnload
@@ -766,7 +764,7 @@
         BOOL isUIAccessibilityAnnouncementNotification = (&UIAccessibilityAnnouncementNotification != NULL);
         if (isUIAccessibilityAnnouncementNotification) {
             dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 500ull * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
-                    UIAccessibilityPostNotification (UIAccessibilityAnnouncementNotification, NSLocalizedString (@"timed recording complete", nil));
+                    UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, NSLocalizedString(@"timed recording complete", nil));
                 });
         }
     } else {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegate.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegate.h b/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegate.h
index e177c63..0401136 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegate.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegate.h
@@ -30,7 +30,6 @@
 
 - (NSString*)pathForResource:(NSString*)resourcepath;
 - (id)getCommandInstance:(NSString*)pluginName;
-- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className CDV_DEPRECATED(2.2, "Use CDVViewController to register plugins, or use config.xml.");
 
 // Plugins should not be using this interface to call other plugins since it
 // will result in bogus callbacks being made.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegateImpl.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegateImpl.m b/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegateImpl.m
index e399289..fa0e5e0 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegateImpl.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegateImpl.m
@@ -55,7 +55,11 @@
 
 - (void)evalJsHelper2:(NSString*)js
 {
+    CDV_EXEC_LOG(@"Exec: evalling: %@", [js substringToIndex:MIN([js length], 160)]);
     NSString* commandsJSON = [_viewController.webView stringByEvaluatingJavaScriptFromString:js];
+    if ([commandsJSON length] > 0) {
+        CDV_EXEC_LOG(@"Exec: Retrieved new exec messages by chaining.");
+    }
 
     [_commandQueue enqueCommandBatch:commandsJSON];
 }
@@ -78,21 +82,16 @@
 
 - (void)sendPluginResult:(CDVPluginResult*)result callbackId:(NSString*)callbackId
 {
+    CDV_EXEC_LOG(@"Exec(%@): Sending result. Status=%@", callbackId, result.status);
     // This occurs when there is are no win/fail callbacks for the call.
-    if ([@"INVALID" isEqualToString:callbackId]) {
+    if ([@"INVALID" isEqualToString : callbackId]) {
         return;
     }
     int status = [result.status intValue];
     BOOL keepCallback = [result.keepCallback boolValue];
-    id message = result.message == nil ? [NSNull null] : result.message;
+    NSString* argumentsAsJSON = [result argumentsAsJSON];
 
-    // Use an array to encode the message as JSON.
-    message = [NSArray arrayWithObject:message];
-    NSString* encodedMessage = [message JSONString];
-    // And then strip off the outer []s.
-    encodedMessage = [encodedMessage substringWithRange:NSMakeRange(1, [encodedMessage length] - 2)];
-    NSString* js = [NSString stringWithFormat:@"cordova.require('cordova/exec').nativeCallback('%@',%d,%@,%d)",
-        callbackId, status, encodedMessage, keepCallback];
+    NSString* js = [NSString stringWithFormat:@"cordova.require('cordova/exec').nativeCallback('%@',%d,%@,%d)", callbackId, status, argumentsAsJSON, keepCallback];
 
     [self evalJsHelper:js];
 }
@@ -122,11 +121,6 @@
     return [_viewController getCommandInstance:pluginName];
 }
 
-- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className
-{
-    [_viewController registerPlugin:plugin withClassName:className];
-}
-
 - (void)runInBackground:(void (^)())block
 {
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.h b/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.h
index ebdf844..27c47b5 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.h
@@ -22,13 +22,7 @@
 @class CDVInvokedUrlCommand;
 @class CDVViewController;
 
-@interface CDVCommandQueue : NSObject {
-    @private
-    NSInteger _lastCommandQueueFlushRequestId;
-    __weak CDVViewController* _viewController;
-    NSMutableArray* _queue;
-    BOOL _currentlyExecuting;
-}
+@interface CDVCommandQueue : NSObject
 
 @property (nonatomic, readonly) BOOL currentlyExecuting;
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.m b/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.m
index a8a58b7..1a0dfa0 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCommandQueue.m
@@ -23,6 +23,14 @@
 #import "CDVViewController.h"
 #import "CDVCommandDelegateImpl.h"
 
+@interface CDVCommandQueue () {
+    NSInteger _lastCommandQueueFlushRequestId;
+    __weak CDVViewController* _viewController;
+    NSMutableArray* _queue;
+    BOOL _currentlyExecuting;
+}
+@end
+
 @implementation CDVCommandQueue
 
 @synthesize currentlyExecuting = _currentlyExecuting;
@@ -74,6 +82,9 @@
         @"cordova.require('cordova/exec').nativeFetchMessages()"];
 
     [self enqueCommandBatch:queuedCommandsJSON];
+    if ([queuedCommandsJSON length] > 0) {
+        CDV_EXEC_LOG(@"Exec: Retrieved new exec messages by request.");
+    }
 }
 
 - (void)executePending
@@ -92,13 +103,15 @@
             // Iterate over and execute all of the commands.
             for (NSArray* jsonEntry in commandBatch) {
                 CDVInvokedUrlCommand* command = [CDVInvokedUrlCommand commandFromJson:jsonEntry];
+                CDV_EXEC_LOG(@"Exec(%@): Calling %@.%@", command.callbackId, command.className, command.methodName);
+
                 if (![self execute:command]) {
 #ifdef DEBUG
                         NSString* commandJson = [jsonEntry JSONString];
                         static NSUInteger maxLogLength = 1024;
                         NSString* commandString = ([commandJson length] > maxLogLength) ?
-                        [NSString stringWithFormat:@"%@[...]", [commandJson substringToIndex:maxLogLength]] :
-                        commandJson;
+                            [NSString stringWithFormat:@"%@[...]", [commandJson substringToIndex:maxLogLength]] :
+                            commandJson;
 
                         DLog(@"FAILED pluginJSON = %@", commandString);
 #endif

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.m b/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.m
index 6fd5913..ffc8ede 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.m
@@ -52,7 +52,7 @@
     } else if ([elementName isEqualToString:@"plugin"]) {
         NSString* name = [attributeDict[@"name"] lowercaseString];
         pluginsDict[name] = attributeDict[@"value"];
-        if ([@"true" isEqualToString:attributeDict[@"onload"]]) {
+        if ([@"true" isEqualToString : attributeDict[@"onload"]]) {
             [self.startupPluginNames addObject:name];
         }
     } else if ([elementName isEqualToString:@"access"]) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVConnection.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVConnection.m b/lib/cordova-ios/CordovaLib/Classes/CDVConnection.m
index 3030711..b3f5cab 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVConnection.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVConnection.m
@@ -52,7 +52,8 @@
             return @"none";
 
         case ReachableViaWWAN:
-            return @"2g"; // no generic default, so we use the lowest common denominator
+            // Return value of '2g' is deprecated as of 2.6.0 and will be replaced with 'cellular' in 3.0.0
+            return @"2g";
 
         case ReachableViaWiFi:
             return @"wifi";
@@ -66,7 +67,8 @@
 {
     return [theConnectionType isEqualToString:@"2g"] ||
            [theConnectionType isEqualToString:@"3g"] ||
-           [theConnectionType isEqualToString:@"4g"];
+           [theConnectionType isEqualToString:@"4g"] ||
+           [theConnectionType isEqualToString:@"cellular"];
 }
 
 - (void)updateReachability:(CDVReachability*)reachability
@@ -111,6 +113,7 @@
         self.internetReach = [CDVReachability reachabilityForInternetConnection];
         self.connectionType = [self w3cConnectionTypeFor:self.internetReach];
         [self.internetReach startNotifier];
+        [self printDeprecationNotice];
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateConnectionType:)
                                                      name:kReachabilityChangedNotification object:nil];
         if (&UIApplicationDidEnterBackgroundNotification && &UIApplicationWillEnterForegroundNotification) {
@@ -121,4 +124,9 @@
     return self;
 }
 
+- (void)printDeprecationNotice
+{
+    NSLog(@"DEPRECATION NOTICE: The Connection ReachableViaWWAN return value of '2g' is deprecated as of Cordova version 2.6.0 and will be changed to 'cellular' in a future release. ");
+}
+
 @end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVContact.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVContact.m b/lib/cordova-ios/CordovaLib/Classes/CDVContact.m
index 9efaf10..3844525 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVContact.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVContact.m
@@ -38,7 +38,9 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
     if ((self = [super init]) != nil) {
         ABRecordRef rec = ABPersonCreate();
         self.record = rec;
-        CFRelease(rec);
+        if (rec) {
+            CFRelease(rec);
+        }
     }
     return self;
 }
@@ -167,9 +169,9 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
     if (org_apache_cordova_contacts_objectAndProperties == nil) {
         org_apache_cordova_contacts_objectAndProperties = [NSDictionary dictionaryWithObjectsAndKeys:
             [NSArray arrayWithObjects:kW3ContactGivenName, kW3ContactFamilyName,
-                kW3ContactMiddleName, kW3ContactHonorificPrefix, kW3ContactHonorificSuffix, kW3ContactFormattedName, nil], kW3ContactName,
+            kW3ContactMiddleName, kW3ContactHonorificPrefix, kW3ContactHonorificSuffix, kW3ContactFormattedName, nil], kW3ContactName,
             [NSArray arrayWithObjects:kW3ContactStreetAddress, kW3ContactLocality, kW3ContactRegion,
-                kW3ContactPostalCode, kW3ContactCountry, /*kW3ContactAddressFormatted,*/ nil], kW3ContactAddresses,
+            kW3ContactPostalCode, kW3ContactCountry, /*kW3ContactAddressFormatted,*/ nil], kW3ContactAddresses,
             [NSArray arrayWithObjects:kW3ContactOrganizationName, kW3ContactTitle, kW3ContactDepartment, nil], kW3ContactOrganizations,
             [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary, nil], kW3ContactPhoneNumbers,
             [NSArray arrayWithObjects:kW3ContactFieldType, kW3ContactFieldValue, kW3ContactFieldPrimary, nil], kW3ContactEmails,
@@ -228,7 +230,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
         NSArray* propArray = [[CDVContact defaultObjectAndProperties] objectForKey:kW3ContactName];
 
         for (id i in propArray) {
-            if (![(NSString*) i isEqualToString:kW3ContactFormattedName]) { // kW3ContactFormattedName is generated from ABRecordCopyCompositeName() and can't be set
+            if (![(NSString*)i isEqualToString : kW3ContactFormattedName]) { // kW3ContactFormattedName is generated from ABRecordCopyCompositeName() and can't be set
                 [self setValue:[dict valueForKey:i] forProperty:(ABPropertyID)[(NSNumber*)[[CDVContact defaultW3CtoAB] objectForKey:i] intValue]
                       inRecord:person asUpdate:bUpdate];
             }
@@ -298,9 +300,9 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
             bRemove = YES;
         }
         if ([dict isKindOfClass:[NSDictionary class]] || (bRemove == YES)) {
-            [self setValue:(bRemove ? @"":[dict valueForKey:@"name"]) forProperty:kABPersonOrganizationProperty inRecord:person asUpdate:bUpdate];
-            [self setValue:(bRemove ? @"":[dict valueForKey:kW3ContactTitle]) forProperty:kABPersonJobTitleProperty inRecord:person asUpdate:bUpdate];
-            [self setValue:(bRemove ? @"":[dict valueForKey:kW3ContactDepartment]) forProperty:kABPersonDepartmentProperty inRecord:person asUpdate:bUpdate];
+            [self setValue:(bRemove ? @"" : [dict valueForKey:@"name"]) forProperty:kABPersonOrganizationProperty inRecord:person asUpdate:bUpdate];
+            [self setValue:(bRemove ? @"" : [dict valueForKey:kW3ContactTitle]) forProperty:kABPersonJobTitleProperty inRecord:person asUpdate:bUpdate];
+            [self setValue:(bRemove ? @"" : [dict valueForKey:kW3ContactDepartment]) forProperty:kABPersonDepartmentProperty inRecord:person asUpdate:bUpdate];
         }
     }
     // add dates
@@ -658,7 +660,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
                             [dict setObject:setValue forKey:(NSString*)[[CDVContact defaultW3CtoAB] valueForKey:(NSString*)k]];
                         } else if ((value == nil) || ([value isKindOfClass:[NSString class]] && ([value length] != 0))) {
                             // value not provided in contact dictionary - if prop exists in AB dictionary, preserve it
-                            valueAB = [(__bridge NSDictionary*) existingDictionary valueForKey:[[CDVContact defaultW3CtoAB] valueForKey:k]];
+                            valueAB = [(__bridge NSDictionary*)existingDictionary valueForKey : [[CDVContact defaultW3CtoAB] valueForKey:k]];
                             if (valueAB != nil) {
                                 [dict setValue:valueAB forKey:[[CDVContact defaultW3CtoAB] valueForKey:k]];
                             }
@@ -893,7 +895,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
     if (data != nil) {
         [nc setObject:data forKey:kW3ContactName];
     }
-    if ([self.returnFields objectForKey:kW3ContactDisplayName] && ((data == nil) || ([(NSDictionary*) data objectForKey:kW3ContactFormattedName] == [NSNull null]))) {
+    if ([self.returnFields objectForKey:kW3ContactDisplayName] && ((data == nil) || ([(NSDictionary*)data objectForKey : kW3ContactFormattedName] == [NSNull null]))) {
         // user asked for displayName which iOS doesn't support but there is no other name data being returned
         // try and use Composite Name so some name is returned
         id tryName = (__bridge_transfer NSString*)ABRecordCopyCompositeName(self.record);
@@ -1114,7 +1116,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
             // always set id
             value = [NSNumber numberWithUnsignedInt:ABMultiValueGetIdentifierAtIndex(multi, i)];
             [newDict setObject:(value != nil) ? value:[NSNull null] forKey:kW3ContactFieldId];
-            [(NSMutableArray*) valuesArray addObject:newDict];
+            [(NSMutableArray*)valuesArray addObject : newDict];
         }
     } else {
         valuesArray = [NSNull null];
@@ -1188,7 +1190,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
             }
 
             if ([newAddress count] > 0) { // ?? this will always be true since we set id,label,primary field??
-                [(NSMutableArray*) addresses addObject:newAddress];
+                [(NSMutableArray*)addresses addObject : newAddress];
             }
             CFRelease(dict);
         } // end of loop through addresses
@@ -1244,7 +1246,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
                 bFound = CFDictionaryGetValueIfPresent(dict, kABPersonInstantMessageServiceKey, (void*)&value);
                 if (bFound && (value != NULL)) {
                     CFRetain(value);
-                    [newDict setObject:(id)[[CDVContact class] convertPropertyLabelToContactType:(__bridge NSString*)value] forKey:kW3ContactFieldType];
+                    [newDict setObject:(id)[[CDVContact class] convertPropertyLabelToContactType : (__bridge NSString*)value] forKey:kW3ContactFieldType];
                     CFRelease(value);
                 } else {
                     [newDict setObject:[NSNull null] forKey:kW3ContactFieldType];
@@ -1254,7 +1256,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
             id identifier = [NSNumber numberWithUnsignedInt:ABMultiValueGetIdentifierAtIndex(multi, i)];
             [newDict setObject:(identifier != nil) ? identifier:[NSNull null] forKey:kW3ContactFieldId];
 
-            [(NSMutableArray*) imArray addObject:newDict];
+            [(NSMutableArray*)imArray addObject : newDict];
             CFRelease(dict);
         }
     } else {
@@ -1308,7 +1310,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
         [newDict setObject:@"false" forKey:kW3ContactFieldPrimary];
         [newDict setObject:[NSNull null] forKey:kW3ContactFieldType];
         array = [NSMutableArray arrayWithCapacity:1];
-        [(NSMutableArray*) array addObject:newDict];
+        [(NSMutableArray*)array addObject : newDict];
     } else {
         array = [NSNull null];
     }
@@ -1327,7 +1329,7 @@ static NSDictionary* org_apache_cordova_contacts_defaultFields = nil;
         NSData* data = (__bridge NSData*)photoData;
         // write to temp directory and store URI in photos array
         // get the temp directory path
-        NSString* docsPath = [NSTemporaryDirectory ()stringByStandardizingPath];
+        NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath];
         NSError* err = nil;
         NSString* filePath = [NSString stringWithFormat:@"%@/photo_XXXXX", docsPath];
         char template[filePath.length + 1];

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVContacts.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVContacts.h b/lib/cordova-ios/CordovaLib/Classes/CDVContacts.h
index 17470c0..0342f5b 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVContacts.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVContacts.h
@@ -24,9 +24,9 @@
 #import "CDVContact.h"
 
 @interface CDVContacts : CDVPlugin <ABNewPersonViewControllerDelegate,
-    ABPersonViewControllerDelegate,
-    ABPeoplePickerNavigationControllerDelegate
-    >
+                         ABPersonViewControllerDelegate,
+                         ABPeoplePickerNavigationControllerDelegate
+                         >
 {
     ABAddressBookRef addressBook;
 }
@@ -63,7 +63,7 @@
 
 - (void)newPersonViewController:(ABNewPersonViewController*)newPersonViewController didCompleteWithNewPerson:(ABRecordRef)person;
 - (BOOL)personViewController:(ABPersonViewController*)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person
-   property                 :(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue;
+                    property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifierForValue;
 
 /*
  * search - searches for contacts.  Only person records are currently supported.
@@ -140,9 +140,9 @@
 - (CDVAddressBookAccessError*)initWithCode:(CDVContactError)code;
 @end
 
-typedef void (^CDVAddressBookWorkerBlock)(
-    ABAddressBookRef addressBook,
-    CDVAddressBookAccessError * error
+typedef void (^ CDVAddressBookWorkerBlock)(
+    ABAddressBookRef         addressBook,
+    CDVAddressBookAccessError* error
     );
 @interface CDVAddressBookHelper : NSObject
 {}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVContacts.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVContacts.m b/lib/cordova-ios/CordovaLib/Classes/CDVContacts.m
index 3faf6ba..6cb9f08 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVContacts.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVContacts.m
@@ -77,26 +77,26 @@
     CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init];
     CDVContacts* __weak weakSelf = self;  // play it safe to avoid retain cycles
 
-    [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError * errCode) {
-            if (addrBook == NULL) {
-                // permission was denied or other error just return (no error callback)
-                return;
-            }
-            CDVNewContactsController* npController = [[CDVNewContactsController alloc] init];
-            npController.addressBook = addrBook; // a CF retaining assign
-            CFRelease (addrBook);
+    [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errCode) {
+        if (addrBook == NULL) {
+            // permission was denied or other error just return (no error callback)
+            return;
+        }
+        CDVNewContactsController* npController = [[CDVNewContactsController alloc] init];
+        npController.addressBook = addrBook;     // a CF retaining assign
+        CFRelease(addrBook);
 
-            npController.newPersonViewDelegate = self;
-            npController.callbackId = callbackId;
+        npController.newPersonViewDelegate = self;
+        npController.callbackId = callbackId;
 
-            UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:npController];
+        UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:npController];
 
-            if ([weakSelf.viewController respondsToSelector:@selector(presentViewController:::)]) {
-                [weakSelf.viewController presentViewController:navController animated:YES completion:nil];
-            } else {
-                [weakSelf.viewController presentModalViewController:navController animated:YES];
-            }
-        }];
+        if ([weakSelf.viewController respondsToSelector:@selector(presentViewController:::)]) {
+            [weakSelf.viewController presentViewController:navController animated:YES completion:nil];
+        } else {
+            [weakSelf.viewController presentModalViewController:navController animated:YES];
+        }
+    }];
 }
 
 - (void)newPersonViewController:(ABNewPersonViewController*)newPersonViewController didCompleteWithNewPerson:(ABRecordRef)person
@@ -130,48 +130,48 @@
     CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init];
     CDVContacts* __weak weakSelf = self;  // play it safe to avoid retain cycles
 
-    [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError * errCode) {
-            if (addrBook == NULL) {
-                // permission was denied or other error - return error
-                CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:errCode ? errCode.errorCode:UNKNOWN_ERROR];
-                [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
-                return;
-            }
-            ABRecordRef rec = ABAddressBookGetPersonWithRecordID (addrBook, recordID);
-
-            if (rec) {
-                CDVDisplayContactViewController* personController = [[CDVDisplayContactViewController alloc] init];
-                personController.displayedPerson = rec;
-                personController.personViewDelegate = self;
-                personController.allowsEditing = NO;
+    [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errCode) {
+        if (addrBook == NULL) {
+            // permission was denied or other error - return error
+            CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:errCode ? errCode.errorCode:UNKNOWN_ERROR];
+            [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
+            return;
+        }
+        ABRecordRef rec = ABAddressBookGetPersonWithRecordID(addrBook, recordID);
 
-                // create this so DisplayContactViewController will have a "back" button.
-                UIViewController* parentController = [[UIViewController alloc] init];
-                UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:parentController];
+        if (rec) {
+            CDVDisplayContactViewController* personController = [[CDVDisplayContactViewController alloc] init];
+            personController.displayedPerson = rec;
+            personController.personViewDelegate = self;
+            personController.allowsEditing = NO;
 
-                [navController pushViewController:personController animated:YES];
+            // create this so DisplayContactViewController will have a "back" button.
+            UIViewController* parentController = [[UIViewController alloc] init];
+            UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:parentController];
 
-                if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) {
-                    [self.viewController presentViewController:navController animated:YES completion:nil];
-                } else {
-                    [self.viewController presentModalViewController:navController animated:YES];
-                }
+            [navController pushViewController:personController animated:YES];
 
-                if (bEdit) {
-                    // create the editing controller and push it onto the stack
-                    ABPersonViewController* editPersonController = [[ABPersonViewController alloc] init];
-                    editPersonController.displayedPerson = rec;
-                    editPersonController.personViewDelegate = self;
-                    editPersonController.allowsEditing = YES;
-                    [navController pushViewController:editPersonController animated:YES];
-                }
+            if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) {
+                [self.viewController presentViewController:navController animated:YES completion:nil];
             } else {
-                // no record, return error
-                CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:UNKNOWN_ERROR];
-                [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
+                [self.viewController presentModalViewController:navController animated:YES];
             }
-            CFRelease (addrBook);
-        }];
+
+            if (bEdit) {
+                // create the editing controller and push it onto the stack
+                ABPersonViewController* editPersonController = [[ABPersonViewController alloc] init];
+                editPersonController.displayedPerson = rec;
+                editPersonController.personViewDelegate = self;
+                editPersonController.allowsEditing = YES;
+                [navController pushViewController:editPersonController animated:YES];
+            }
+        } else {
+            // no record, return error
+            CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:UNKNOWN_ERROR];
+            [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
+        }
+        CFRelease(addrBook);
+    }];
 }
 
 - (BOOL)personViewController:(ABPersonViewController*)personViewController shouldPerformDefaultActionForPerson:(ABRecordRef)person
@@ -284,95 +284,95 @@
     NSDictionary* findOptions = [command.arguments objectAtIndex:1 withDefault:[NSNull null]];
 
     [self.commandDelegate runInBackground:^{
-            // from Apple:  Important You must ensure that an instance of ABAddressBookRef is used by only one thread.
-            // which is why address book is created within the dispatch queue.
-            // more details here: http: //blog.byadrian.net/2012/05/05/ios-addressbook-framework-and-gcd/
-            CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init];
-            CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles
-            // it gets uglier, block within block.....
-            [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError * errCode) {
-                    if (addrBook == NULL) {
-                        // permission was denied or other error - return error
-                        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:errCode ? errCode.errorCode:UNKNOWN_ERROR];
-                        [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
-                        return;
-                    }
+        // from Apple:  Important You must ensure that an instance of ABAddressBookRef is used by only one thread.
+        // which is why address book is created within the dispatch queue.
+        // more details here: http: //blog.byadrian.net/2012/05/05/ios-addressbook-framework-and-gcd/
+        CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init];
+        CDVContacts* __weak weakSelf = self;     // play it safe to avoid retain cycles
+        // it gets uglier, block within block.....
+        [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errCode) {
+            if (addrBook == NULL) {
+                // permission was denied or other error - return error
+                CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageToErrorObject:errCode ? errCode.errorCode:UNKNOWN_ERROR];
+                [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
+                return;
+            }
 
-                    NSArray* foundRecords = nil;
-                    // get the findOptions values
-                    BOOL multiple = NO; // default is false
-                    NSString* filter = nil;
-                    if (![findOptions isKindOfClass:[NSNull class]]) {
-                        id value = nil;
-                        filter = (NSString*)[findOptions objectForKey:@"filter"];
-                        value = [findOptions objectForKey:@"multiple"];
-                        if ([value isKindOfClass:[NSNumber class]]) {
-                            // multiple is a boolean that will come through as an NSNumber
-                            multiple = [(NSNumber*) value boolValue];
-                            // NSLog(@"multiple is: %d", multiple);
-                        }
-                    }
+            NSArray* foundRecords = nil;
+            // get the findOptions values
+            BOOL multiple = NO;         // default is false
+            NSString* filter = nil;
+            if (![findOptions isKindOfClass:[NSNull class]]) {
+                id value = nil;
+                filter = (NSString*)[findOptions objectForKey:@"filter"];
+                value = [findOptions objectForKey:@"multiple"];
+                if ([value isKindOfClass:[NSNumber class]]) {
+                    // multiple is a boolean that will come through as an NSNumber
+                    multiple = [(NSNumber*)value boolValue];
+                    // NSLog(@"multiple is: %d", multiple);
+                }
+            }
 
-                    NSDictionary* returnFields = [[CDVContact class] calcReturnFields:fields];
-
-                    NSMutableArray* matches = nil;
-                    if (!filter || [filter isEqualToString:@""]) {
-                        // get all records
-                        foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople (addrBook);
-                        if (foundRecords && [foundRecords count] > 0) {
-                            // create Contacts and put into matches array
-                            // doesn't make sense to ask for all records when multiple == NO but better check
-                            int xferCount = multiple == YES ? [foundRecords count]:1;
-                            matches = [NSMutableArray arrayWithCapacity:xferCount];
-
-                            for (int k = 0; k < xferCount; k++) {
-                                CDVContact* xferContact = [[CDVContact alloc] initFromABRecord:(__bridge ABRecordRef)[foundRecords objectAtIndex:k]];
-                                [matches addObject:xferContact];
-                                xferContact = nil;
-                            }
-                        }
-                    } else {
-                        foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople (addrBook);
-                        matches = [NSMutableArray arrayWithCapacity:1];
-                        BOOL bFound = NO;
-                        int testCount = [foundRecords count];
-
-                        for (int j = 0; j < testCount; j++) {
-                            CDVContact* testContact = [[CDVContact alloc] initFromABRecord:(__bridge ABRecordRef)[foundRecords objectAtIndex:j]];
-                            if (testContact) {
-                                bFound = [testContact foundValue:filter inFields:returnFields];
-                                if (bFound) {
-                                    [matches addObject:testContact];
-                                }
-                                testContact = nil;
-                            }
-                        }
+            NSDictionary* returnFields = [[CDVContact class] calcReturnFields:fields];
+
+            NSMutableArray* matches = nil;
+            if (!filter || [filter isEqualToString:@""]) {
+                // get all records
+                foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook);
+                if (foundRecords && ([foundRecords count] > 0)) {
+                    // create Contacts and put into matches array
+                    // doesn't make sense to ask for all records when multiple == NO but better check
+                    int xferCount = multiple == YES ? [foundRecords count] : 1;
+                    matches = [NSMutableArray arrayWithCapacity:xferCount];
+
+                    for (int k = 0; k < xferCount; k++) {
+                        CDVContact* xferContact = [[CDVContact alloc] initFromABRecord:(__bridge ABRecordRef)[foundRecords objectAtIndex:k]];
+                        [matches addObject:xferContact];
+                        xferContact = nil;
                     }
-                    NSMutableArray* returnContacts = [NSMutableArray arrayWithCapacity:1];
-
-                    if (matches != nil && [matches count] > 0) {
-                        // convert to JS Contacts format and return in callback
-                        // - returnFields  determines what properties to return
-                        @autoreleasepool {
-                            int count = multiple == YES ? [matches count]:1;
-
-                            for (int i = 0; i < count; i++) {
-                                CDVContact* newContact = [matches objectAtIndex:i];
-                                NSDictionary* aContact = [newContact toDictionary:returnFields];
-                                [returnContacts addObject:aContact];
-                            }
+                }
+            } else {
+                foundRecords = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addrBook);
+                matches = [NSMutableArray arrayWithCapacity:1];
+                BOOL bFound = NO;
+                int testCount = [foundRecords count];
+
+                for (int j = 0; j < testCount; j++) {
+                    CDVContact* testContact = [[CDVContact alloc] initFromABRecord:(__bridge ABRecordRef)[foundRecords objectAtIndex:j]];
+                    if (testContact) {
+                        bFound = [testContact foundValue:filter inFields:returnFields];
+                        if (bFound) {
+                            [matches addObject:testContact];
                         }
+                        testContact = nil;
                     }
-                    // return found contacts (array is empty if no contacts found)
-                    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:returnContacts];
-                    [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
-                    // NSLog(@"findCallback string: %@", jsString);
-
-                    if (addrBook) {
-                        CFRelease (addrBook);
+                }
+            }
+            NSMutableArray* returnContacts = [NSMutableArray arrayWithCapacity:1];
+
+            if ((matches != nil) && ([matches count] > 0)) {
+                // convert to JS Contacts format and return in callback
+                // - returnFields  determines what properties to return
+                @autoreleasepool {
+                    int count = multiple == YES ? [matches count] : 1;
+
+                    for (int i = 0; i < count; i++) {
+                        CDVContact* newContact = [matches objectAtIndex:i];
+                        NSDictionary* aContact = [newContact toDictionary:returnFields];
+                        [returnContacts addObject:aContact];
                     }
-                }];
-        }]; // end of workQueue block
+                }
+            }
+            // return found contacts (array is empty if no contacts found)
+            CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:returnContacts];
+            [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
+            // NSLog(@"findCallback string: %@", jsString);
+
+            if (addrBook) {
+                CFRelease(addrBook);
+            }
+        }];
+    }];     // end of workQueue block
 
     return;
 }
@@ -383,81 +383,10 @@
     NSDictionary* contactDict = [command.arguments objectAtIndex:0];
 
     [self.commandDelegate runInBackground:^{
-            CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init];
-            CDVContacts* __weak weakSelf = self; // play it safe to avoid retain cycles
-
-            [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError * errorCode) {
-                    CDVPluginResult* result = nil;
-                    if (addrBook == NULL) {
-                        // permission was denied or other error - return error
-                        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode ? errorCode.errorCode:UNKNOWN_ERROR];
-                        [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
-                        return;
-                    }
-
-                    bool bIsError = FALSE, bSuccess = FALSE;
-                    BOOL bUpdate = NO;
-                    CDVContactError errCode = UNKNOWN_ERROR;
-                    CFErrorRef error;
-                    NSNumber* cId = [contactDict valueForKey:kW3ContactId];
-                    CDVContact* aContact = nil;
-                    ABRecordRef rec = nil;
-                    if (cId && ![cId isKindOfClass:[NSNull class]]) {
-                        rec = ABAddressBookGetPersonWithRecordID (addrBook, [cId intValue]);
-                        if (rec) {
-                            aContact = [[CDVContact alloc] initFromABRecord:rec];
-                            bUpdate = YES;
-                        }
-                    }
-                    if (!aContact) {
-                        aContact = [[CDVContact alloc] init];
-                    }
-
-                    bSuccess = [aContact setFromContactDict:contactDict asUpdate:bUpdate];
-                    if (bSuccess) {
-                        if (!bUpdate) {
-                            bSuccess = ABAddressBookAddRecord (addrBook, [aContact record], &error);
-                        }
-                        if (bSuccess) {
-                            bSuccess = ABAddressBookSave (addrBook, &error);
-                        }
-                        if (!bSuccess) { // need to provide error codes
-                            bIsError = TRUE;
-                            errCode = IO_ERROR;
-                        } else {
-                            // give original dictionary back?  If generate dictionary from saved contact, have no returnFields specified
-                            // so would give back all fields (which W3C spec. indicates is not desired)
-                            // for now (while testing) give back saved, full contact
-                            NSDictionary* newContact = [aContact toDictionary:[CDVContact defaultFields]];
-                            // NSString* contactStr = [newContact JSONRepresentation];
-                            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:newContact];
-                        }
-                    } else {
-                        bIsError = TRUE;
-                        errCode = IO_ERROR;
-                    }
-                    CFRelease (addrBook);
-
-                    if (bIsError) {
-                        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errCode];
-                    }
-
-                    if (result) {
-                        [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
-                    }
-                }];
-        }]; // end of  queue
-}
-
-- (void)remove:(CDVInvokedUrlCommand*)command
-{
-    NSString* callbackId = command.callbackId;
-    NSNumber* cId = [command.arguments objectAtIndex:0];
-
-    CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init];
-    CDVContacts* __weak weakSelf = self;  // play it safe to avoid retain cycles
+        CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init];
+        CDVContacts* __weak weakSelf = self;     // play it safe to avoid retain cycles
 
-    [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError * errorCode) {
+        [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errorCode) {
             CDVPluginResult* result = nil;
             if (addrBook == NULL) {
                 // permission was denied or other error - return error
@@ -467,50 +396,121 @@
             }
 
             bool bIsError = FALSE, bSuccess = FALSE;
+            BOOL bUpdate = NO;
             CDVContactError errCode = UNKNOWN_ERROR;
             CFErrorRef error;
+            NSNumber* cId = [contactDict valueForKey:kW3ContactId];
+            CDVContact* aContact = nil;
             ABRecordRef rec = nil;
-            if (cId && ![cId isKindOfClass:[NSNull class]] && ([cId intValue] != kABRecordInvalidID)) {
-                rec = ABAddressBookGetPersonWithRecordID (addrBook, [cId intValue]);
+            if (cId && ![cId isKindOfClass:[NSNull class]]) {
+                rec = ABAddressBookGetPersonWithRecordID(addrBook, [cId intValue]);
                 if (rec) {
-                    bSuccess = ABAddressBookRemoveRecord (addrBook, rec, &error);
-                    if (!bSuccess) {
-                        bIsError = TRUE;
-                        errCode = IO_ERROR;
-                    } else {
-                        bSuccess = ABAddressBookSave (addrBook, &error);
-                        if (!bSuccess) {
-                            bIsError = TRUE;
-                            errCode = IO_ERROR;
-                        } else {
-                            // set id to null
-                            // [contactDict setObject:[NSNull null] forKey:kW3ContactId];
-                            // result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary: contactDict];
-                            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
-                            // NSString* contactStr = [contactDict JSONRepresentation];
-                        }
-                    }
-                } else {
-                    // no record found return error
+                    aContact = [[CDVContact alloc] initFromABRecord:rec];
+                    bUpdate = YES;
+                }
+            }
+            if (!aContact) {
+                aContact = [[CDVContact alloc] init];
+            }
+
+            bSuccess = [aContact setFromContactDict:contactDict asUpdate:bUpdate];
+            if (bSuccess) {
+                if (!bUpdate) {
+                    bSuccess = ABAddressBookAddRecord(addrBook, [aContact record], &error);
+                }
+                if (bSuccess) {
+                    bSuccess = ABAddressBookSave(addrBook, &error);
+                }
+                if (!bSuccess) {         // need to provide error codes
                     bIsError = TRUE;
-                    errCode = UNKNOWN_ERROR;
+                    errCode = IO_ERROR;
+                } else {
+                    // give original dictionary back?  If generate dictionary from saved contact, have no returnFields specified
+                    // so would give back all fields (which W3C spec. indicates is not desired)
+                    // for now (while testing) give back saved, full contact
+                    NSDictionary* newContact = [aContact toDictionary:[CDVContact defaultFields]];
+                    // NSString* contactStr = [newContact JSONRepresentation];
+                    result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:newContact];
                 }
             } else {
-                // invalid contact id provided
                 bIsError = TRUE;
-                errCode = INVALID_ARGUMENT_ERROR;
+                errCode = IO_ERROR;
             }
+            CFRelease(addrBook);
 
-            if (addrBook) {
-                CFRelease (addrBook);
-            }
             if (bIsError) {
                 result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errCode];
             }
+
             if (result) {
                 [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
             }
         }];
+    }];     // end of  queue
+}
+
+- (void)remove:(CDVInvokedUrlCommand*)command
+{
+    NSString* callbackId = command.callbackId;
+    NSNumber* cId = [command.arguments objectAtIndex:0];
+
+    CDVAddressBookHelper* abHelper = [[CDVAddressBookHelper alloc] init];
+    CDVContacts* __weak weakSelf = self;  // play it safe to avoid retain cycles
+
+    [abHelper createAddressBook: ^(ABAddressBookRef addrBook, CDVAddressBookAccessError* errorCode) {
+        CDVPluginResult* result = nil;
+        if (addrBook == NULL) {
+            // permission was denied or other error - return error
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errorCode ? errorCode.errorCode:UNKNOWN_ERROR];
+            [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
+            return;
+        }
+
+        bool bIsError = FALSE, bSuccess = FALSE;
+        CDVContactError errCode = UNKNOWN_ERROR;
+        CFErrorRef error;
+        ABRecordRef rec = nil;
+        if (cId && ![cId isKindOfClass:[NSNull class]] && ([cId intValue] != kABRecordInvalidID)) {
+            rec = ABAddressBookGetPersonWithRecordID(addrBook, [cId intValue]);
+            if (rec) {
+                bSuccess = ABAddressBookRemoveRecord(addrBook, rec, &error);
+                if (!bSuccess) {
+                    bIsError = TRUE;
+                    errCode = IO_ERROR;
+                } else {
+                    bSuccess = ABAddressBookSave(addrBook, &error);
+                    if (!bSuccess) {
+                        bIsError = TRUE;
+                        errCode = IO_ERROR;
+                    } else {
+                        // set id to null
+                        // [contactDict setObject:[NSNull null] forKey:kW3ContactId];
+                        // result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary: contactDict];
+                        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
+                        // NSString* contactStr = [contactDict JSONRepresentation];
+                    }
+                }
+            } else {
+                // no record found return error
+                bIsError = TRUE;
+                errCode = UNKNOWN_ERROR;
+            }
+        } else {
+            // invalid contact id provided
+            bIsError = TRUE;
+            errCode = INVALID_ARGUMENT_ERROR;
+        }
+
+        if (addrBook) {
+            CFRelease(addrBook);
+        }
+        if (bIsError) {
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errCode];
+        }
+        if (result) {
+            [weakSelf.commandDelegate sendPluginResult:result callbackId:callbackId];
+        }
+    }];
     return;
 }
 
@@ -569,24 +569,24 @@
             addressBook = ABAddressBookCreateWithOptions(NULL, &error);
             // NSLog(@"addressBook access: %lu", status);
             ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
-                // callback can occur in background, address book must be accessed on thread it was created on
-                dispatch_sync (dispatch_get_main_queue (), ^{
+                    // callback can occur in background, address book must be accessed on thread it was created on
+                    dispatch_sync(dispatch_get_main_queue(), ^{
                         if (error) {
-                            workerBlock (NULL, [[CDVAddressBookAccessError alloc] initWithCode:UNKNOWN_ERROR]);
+                            workerBlock(NULL, [[CDVAddressBookAccessError alloc] initWithCode:UNKNOWN_ERROR]);
                         } else if (!granted) {
-                            workerBlock (NULL, [[CDVAddressBookAccessError alloc] initWithCode:PERMISSION_DENIED_ERROR]);
+                            workerBlock(NULL, [[CDVAddressBookAccessError alloc] initWithCode:PERMISSION_DENIED_ERROR]);
                         } else {
                             // access granted
-                            workerBlock (addressBook, [[CDVAddressBookAccessError alloc] initWithCode:UNKNOWN_ERROR]);
+                            workerBlock(addressBook, [[CDVAddressBookAccessError alloc] initWithCode:UNKNOWN_ERROR]);
                         }
                     });
-            });
+                });
         } else
 #endif
     {
         // iOS 4 or 5 no checks needed
-        addressBook = ABAddressBookCreate ();
-        workerBlock (addressBook, NULL);
+        addressBook = ABAddressBookCreate();
+        workerBlock(addressBook, NULL);
     }
 }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVEcho.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVEcho.m b/lib/cordova-ios/CordovaLib/Classes/CDVEcho.m
index 916e315..c74990d 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVEcho.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVEcho.m
@@ -51,4 +51,11 @@
     [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
 }
 
+- (void)echoMultiPart:(CDVInvokedUrlCommand*)command
+{
+    CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsMultipart:command.arguments];
+
+    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
+}
+
 @end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVExif.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVExif.h b/lib/cordova-ios/CordovaLib/Classes/CDVExif.h
new file mode 100644
index 0000000..3e8adbd
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVExif.h
@@ -0,0 +1,43 @@
+/*
+ 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.
+ */
+
+#ifndef CordovaLib_ExifData_h
+#define CordovaLib_ExifData_h
+
+// exif data types
+typedef enum exifDataTypes {
+    EDT_UBYTE = 1,      // 8 bit unsigned integer
+    EDT_ASCII_STRING,   // 8 bits containing 7 bit ASCII code, null terminated
+    EDT_USHORT,         // 16 bit unsigned integer
+    EDT_ULONG,          // 32 bit unsigned integer
+    EDT_URATIONAL,      // 2 longs, first is numerator and second is denominator
+    EDT_SBYTE,
+    EDT_UNDEFINED,      // 8 bits
+    EDT_SSHORT,
+    EDT_SLONG,          // 32bit signed integer (2's complement)
+    EDT_SRATIONAL,      // 2 SLONGS, first long is numerator, second is denominator
+    EDT_SINGLEFLOAT,
+    EDT_DOUBLEFLOAT
+} ExifDataTypes;
+
+// maps integer code for exif data types to width in bytes
+static const int DataTypeToWidth[] = {1,1,2,4,8,1,1,2,4,8,4,8};
+
+static const int RECURSE_HORIZON = 8;
+#endif

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVFile.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFile.h b/lib/cordova-ios/CordovaLib/Classes/CDVFile.h
index 4862921..eaf8cbe 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFile.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFile.h
@@ -21,6 +21,7 @@
 #import "CDVPlugin.h"
 
 enum CDVFileError {
+    NO_ERROR = 0,
     NOT_FOUND_ERR = 1,
     SECURITY_ERR = 2,
     ABORT_ERR = 3,
@@ -76,6 +77,7 @@ extern NSString* const kCDVAssetsLibraryPrefix;
 
 - (void)readAsText:(CDVInvokedUrlCommand*)command;
 - (void)readAsDataURL:(CDVInvokedUrlCommand*)command;
+- (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command;
 - (NSString*)getMimeTypeFromPath:(NSString*)fullPath;
 - (void)write:(CDVInvokedUrlCommand*)command;
 - (void)testFileExists:(CDVInvokedUrlCommand*)command;


[03/43] git commit: Use the new style of plugman commands

Posted by an...@apache.org.
Use the new style of plugman commands

The commands have been split into --fetch, --install, --uninstall,
and --remove.


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

Branch: refs/heads/master
Commit: fb7cbc60f783ed0d7ba19d35dc525a4c522df505
Parents: 76ed29c
Author: Braden Shepherdson <br...@gmail.com>
Authored: Tue Mar 26 12:06:13 2013 -0400
Committer: Braden Shepherdson <br...@gmail.com>
Committed: Tue Mar 26 12:06:13 2013 -0400

----------------------------------------------------------------------
 src/plugin.js |   22 +++++++++++++++++++---
 1 files changed, 19 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/fb7cbc60/src/plugin.js
----------------------------------------------------------------------
diff --git a/src/plugin.js b/src/plugin.js
index b323429..03442eb 100644
--- a/src/plugin.js
+++ b/src/plugin.js
@@ -73,9 +73,20 @@ module.exports = function plugin(command, targets, callback) {
             targets.forEach(function(target, index) {
                 hooks.fire('before_plugin_add');
                 var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'plugman.js');
+                var pluginsDir = path.join(projectRoot, 'plugins');
+
+                var lastSlash = target.lastIndexOf('/', target.length - 2);
+
+                // Fetch the plugin first.
+                var cmd = util.format('%s --fetch --plugin "%s" --plugins_dir "%s"', cli, target, pluginsDir);
+                console.log(cmd);
+                var plugin_fetch = shell.exec(cmd, {silent: true});
+                if (plugin_fetch.code > 0) throw new Error('An error occured during plugin fetching:\n' + plugin_fetch.output);
+
                 // Iterate over all platforms in the project and install the plugin.
                 platforms.forEach(function(platform) {
-                    var cmd = util.format('%s --platform %s --project "%s" --plugin "%s" --plugins_dir "%s"', cli, platform, path.join(projectRoot, 'platforms', platform), target, path.join(projectRoot, 'plugins'));
+                    cmd = util.format('%s --platform %s --project "%s" --plugin "%s" --plugins_dir "%s"', cli, platform, path.join(projectRoot, 'platforms', platform), names[index], pluginsDir);
+                    console.log(cmd);
                     var plugin_cli = shell.exec(cmd, {silent:true});
                     if (plugin_cli.code > 0) throw new Error('An error occured during plugin installation for ' + platform + ': ' + plugin_cli.output);
                 });
@@ -107,14 +118,19 @@ module.exports = function plugin(command, targets, callback) {
 
                     // Iterate over all matchin app-plugin platforms in the project and uninstall the
                     // plugin.
+                    var cmd;
                     intersection.forEach(function(platform) {
-                        var cmd = util.format('%s --platform %s --project "%s" --plugin "%s" --remove', cli, platform, path.join(projectRoot, 'platforms', platform), targetPath);
+                        cmd = util.format('%s --platform %s --project "%s" --plugin "%s" --plugins_dir "%s" --uninstall', cli, platform, path.join(projectRoot, 'platforms', platform), targetName, path.join(projectRoot, 'plugins'));
+                        console.log(cmd);
                         var plugin_cli = shell.exec(cmd, {silent:true});
                         if (plugin_cli.code > 0) throw new Error('An error occured during plugin uninstallation for ' + platform + '. ' + plugin_cli.output);
                     });
 
                     // Finally remove the plugin dir from plugins/
-                    shell.rm('-rf', targetPath);
+                    cmd = util.format('%s --plugin "%s" --plugins_dir "%s" --remove', cli, targetName, path.join(projectRoot, 'plugins'));
+                    console.log(cmd);
+                    var plugin_remove = shell.exec(cmd, {silent: true});
+                    if (plugin_remove.code > 0) throw new Error('An error occurred during plugin removal:\n' + plugin_remove.output);
 
                     hooks.fire('after_plugin_rm');
                 } else {


[41/43] git commit: [CB-3238] Update cordova-blackberry to 2.7.0

Posted by an...@apache.org.
[CB-3238] Update cordova-blackberry to 2.7.0


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

Branch: refs/heads/master
Commit: 4ff28b3c03cf8f4c0751f2e022e8b171aba1fdfb
Parents: ee0a502
Author: Michael Brooks <mi...@michaelbrooks.ca>
Authored: Tue Apr 30 13:30:18 2013 -0700
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu May 9 15:56:01 2013 -0700

----------------------------------------------------------------------
 lib/cordova-blackberry/VERSION                     |    2 +-
 .../bin/templates/project/www/VERSION              |    2 +-
 .../bin/templates/project/www/index.html           |    2 +-
 .../ext/src/org/apache/cordova/device/Device.java  |    2 +-
 .../javascript/cordova.blackberry.js               |   16 ++++----------
 5 files changed, 9 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/4ff28b3c/lib/cordova-blackberry/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/VERSION b/lib/cordova-blackberry/VERSION
index 59b7056..24ba9a3 100644
--- a/lib/cordova-blackberry/VERSION
+++ b/lib/cordova-blackberry/VERSION
@@ -1 +1 @@
-2.7.0rc1
+2.7.0

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/4ff28b3c/lib/cordova-blackberry/bin/templates/project/www/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/www/VERSION b/lib/cordova-blackberry/bin/templates/project/www/VERSION
index 59b7056..24ba9a3 100644
--- a/lib/cordova-blackberry/bin/templates/project/www/VERSION
+++ b/lib/cordova-blackberry/bin/templates/project/www/VERSION
@@ -1 +1 @@
-2.7.0rc1
+2.7.0

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/4ff28b3c/lib/cordova-blackberry/bin/templates/project/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/www/index.html b/lib/cordova-blackberry/bin/templates/project/www/index.html
index a56d963..564ce18 100644
--- a/lib/cordova-blackberry/bin/templates/project/www/index.html
+++ b/lib/cordova-blackberry/bin/templates/project/www/index.html
@@ -33,7 +33,7 @@
                 <p class="event received">Device is Ready</p>
             </div>
         </div>
-        <script type="text/javascript" src="cordova-2.7.0rc1.js"></script>
+        <script type="text/javascript" src="cordova-2.7.0.js"></script>
         <script type="text/javascript" src="js/index.js"></script>
         <script type="text/javascript">
             app.initialize();

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/4ff28b3c/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java
index c332cc4..c006b3f 100644
--- a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/device/Device.java
@@ -54,7 +54,7 @@ public final class Device extends Plugin {
 				JSONObject device = new JSONObject();
 				device.put( FIELD_PLATFORM, "BlackBerry");
 				device.put( FIELD_UUID, new Integer( DeviceInfo.getDeviceId()) );
-				device.put( FIELD_CORDOVA, "2.7.0rc1" );
+				device.put( FIELD_CORDOVA, "2.7.0" );
 				device.put( FIELD_MODEL, new String(DeviceInfo.getDeviceName()) );
 				device.put( FIELD_NAME, new String(DeviceInfo.getDeviceName()) );
 				device.put( FIELD_VERSION, new String(DeviceInfo.getSoftwareVersion()) );

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/4ff28b3c/lib/cordova-blackberry/javascript/cordova.blackberry.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/javascript/cordova.blackberry.js b/lib/cordova-blackberry/javascript/cordova.blackberry.js
index cd5878b..73a040d 100644
--- a/lib/cordova-blackberry/javascript/cordova.blackberry.js
+++ b/lib/cordova-blackberry/javascript/cordova.blackberry.js
@@ -1,8 +1,8 @@
 // Platform: blackberry
 
-// commit 4808bdada2a73c3fb2ec69857b8e970414c31d57
+// 2.7.0-4-gabc9de8
 
-// File generated at :: Fri Apr 19 2013 14:51:35 GMT-0700 (PDT)
+// File generated at :: Tue Apr 30 2013 10:52:06 GMT-0700 (PDT)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -1143,8 +1143,6 @@ var CaptureAudioOptions = function(){
     this.limit = 1;
     // Maximum duration of a single sound clip in seconds.
     this.duration = 0;
-    // The selected audio mode. Must match with one of the elements in supportedAudioModes array.
-    this.mode = null;
 };
 
 module.exports = CaptureAudioOptions;
@@ -1185,8 +1183,6 @@ define("cordova/plugin/CaptureImageOptions", function(require, exports, module)
 var CaptureImageOptions = function(){
     // Upper limit of images user can take. Value must be equal or greater than 1.
     this.limit = 1;
-    // The selected image mode. Must match with one of the elements in supportedImageModes array.
-    this.mode = null;
 };
 
 module.exports = CaptureImageOptions;
@@ -1204,8 +1200,6 @@ var CaptureVideoOptions = function(){
     this.limit = 1;
     // Maximum duration of a single video clip in seconds.
     this.duration = 0;
-    // The selected video mode. Must match with one of the elements in supportedVideoModes array.
-    this.mode = null;
 };
 
 module.exports = CaptureVideoOptions;
@@ -5392,7 +5386,7 @@ module.exports = {
                     model: "PlayBook",
                     name: "PlayBook", // deprecated: please use device.model
                     uuid: info.uuid,
-                    cordova: "2.7.0rc1"
+                    cordova: "2.7.0"
                 });
             }),
             request = new blackberry.transport.RemoteFunctionCall("org/apache/cordova/getDeviceInfo");
@@ -9407,7 +9401,7 @@ module.exports = {
             model: "Dev Alpha",
             name: "Dev Alpha", // deprecated: please use device.model
             uuid: blackberry.identity.uuid,
-            cordova: "2.7.0rc1"
+            cordova: "2.7.0"
         });
 
         return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "Device info returned" };
@@ -10887,7 +10881,7 @@ document.addEventListener("DOMContentLoaded", function () {
         xhr.onload = function() {
             // If the response is a JSON string which composes an array, call handlePluginsObject.
             // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
-            var obj = JSON.parse(this.responseText);
+            var obj = this.responseText && JSON.parse(this.responseText);
             if (obj && obj instanceof Array && obj.length > 0) {
                 handlePluginsObject(obj);
             } else {


[42/43] git commit: Version 2.7.0 (npm 2.7.2)

Posted by an...@apache.org.
Version 2.7.0 (npm 2.7.2)


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

Branch: refs/heads/master
Commit: 164d064c988738f9d5091a1a7f8b6213ad46accb
Parents: 4ff28b3
Author: Michael Brooks <mi...@michaelbrooks.ca>
Authored: Tue Apr 30 14:03:22 2013 -0700
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu May 9 15:56:01 2013 -0700

----------------------------------------------------------------------
 VERSION      |    2 +-
 package.json |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/164d064c/VERSION
----------------------------------------------------------------------
diff --git a/VERSION b/VERSION
index 59b7056..24ba9a3 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.7.0rc1
+2.7.0

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/164d064c/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index 2d54e7b..28aec41 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "cordova",
-  "version": "2.7.1-rc.1",
+  "version": "2.7.2",
   "preferGlobal": "true",
   "description": "Cordova command line interface tool",
   "main": "cordova",


[07/43] Move www/ and merges/ into app/.

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/spec/lib/jasmine-1.2.0/jasmine.js
----------------------------------------------------------------------
diff --git a/templates/www/spec/lib/jasmine-1.2.0/jasmine.js b/templates/www/spec/lib/jasmine-1.2.0/jasmine.js
deleted file mode 100644
index 03bf89a..0000000
--- a/templates/www/spec/lib/jasmine-1.2.0/jasmine.js
+++ /dev/null
@@ -1,2529 +0,0 @@
-var isCommonJS = typeof window == "undefined";
-
-/**
- * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
- *
- * @namespace
- */
-var jasmine = {};
-if (isCommonJS) exports.jasmine = jasmine;
-/**
- * @private
- */
-jasmine.unimplementedMethod_ = function() {
-  throw new Error("unimplemented method");
-};
-
-/**
- * Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
- * a plain old variable and may be redefined by somebody else.
- *
- * @private
- */
-jasmine.undefined = jasmine.___undefined___;
-
-/**
- * Show diagnostic messages in the console if set to true
- *
- */
-jasmine.VERBOSE = false;
-
-/**
- * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
- *
- */
-jasmine.DEFAULT_UPDATE_INTERVAL = 250;
-
-/**
- * Default timeout interval in milliseconds for waitsFor() blocks.
- */
-jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
-
-jasmine.getGlobal = function() {
-  function getGlobal() {
-    return this;
-  }
-
-  return getGlobal();
-};
-
-/**
- * Allows for bound functions to be compared.  Internal use only.
- *
- * @ignore
- * @private
- * @param base {Object} bound 'this' for the function
- * @param name {Function} function to find
- */
-jasmine.bindOriginal_ = function(base, name) {
-  var original = base[name];
-  if (original.apply) {
-    return function() {
-      return original.apply(base, arguments);
-    };
-  } else {
-    // IE support
-    return jasmine.getGlobal()[name];
-  }
-};
-
-jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
-jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
-jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
-jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
-
-jasmine.MessageResult = function(values) {
-  this.type = 'log';
-  this.values = values;
-  this.trace = new Error(); // todo: test better
-};
-
-jasmine.MessageResult.prototype.toString = function() {
-  var text = "";
-  for (var i = 0; i < this.values.length; i++) {
-    if (i > 0) text += " ";
-    if (jasmine.isString_(this.values[i])) {
-      text += this.values[i];
-    } else {
-      text += jasmine.pp(this.values[i]);
-    }
-  }
-  return text;
-};
-
-jasmine.ExpectationResult = function(params) {
-  this.type = 'expect';
-  this.matcherName = params.matcherName;
-  this.passed_ = params.passed;
-  this.expected = params.expected;
-  this.actual = params.actual;
-  this.message = this.passed_ ? 'Passed.' : params.message;
-
-  var trace = (params.trace || new Error(this.message));
-  this.trace = this.passed_ ? '' : trace;
-};
-
-jasmine.ExpectationResult.prototype.toString = function () {
-  return this.message;
-};
-
-jasmine.ExpectationResult.prototype.passed = function () {
-  return this.passed_;
-};
-
-/**
- * Getter for the Jasmine environment. Ensures one gets created
- */
-jasmine.getEnv = function() {
-  var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
-  return env;
-};
-
-/**
- * @ignore
- * @private
- * @param value
- * @returns {Boolean}
- */
-jasmine.isArray_ = function(value) {
-  return jasmine.isA_("Array", value);
-};
-
-/**
- * @ignore
- * @private
- * @param value
- * @returns {Boolean}
- */
-jasmine.isString_ = function(value) {
-  return jasmine.isA_("String", value);
-};
-
-/**
- * @ignore
- * @private
- * @param value
- * @returns {Boolean}
- */
-jasmine.isNumber_ = function(value) {
-  return jasmine.isA_("Number", value);
-};
-
-/**
- * @ignore
- * @private
- * @param {String} typeName
- * @param value
- * @returns {Boolean}
- */
-jasmine.isA_ = function(typeName, value) {
-  return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
-};
-
-/**
- * Pretty printer for expecations.  Takes any object and turns it into a human-readable string.
- *
- * @param value {Object} an object to be outputted
- * @returns {String}
- */
-jasmine.pp = function(value) {
-  var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
-  stringPrettyPrinter.format(value);
-  return stringPrettyPrinter.string;
-};
-
-/**
- * Returns true if the object is a DOM Node.
- *
- * @param {Object} obj object to check
- * @returns {Boolean}
- */
-jasmine.isDomNode = function(obj) {
-  return obj.nodeType > 0;
-};
-
-/**
- * Returns a matchable 'generic' object of the class type.  For use in expecations of type when values don't matter.
- *
- * @example
- * // don't care about which function is passed in, as long as it's a function
- * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
- *
- * @param {Class} clazz
- * @returns matchable object of the type clazz
- */
-jasmine.any = function(clazz) {
-  return new jasmine.Matchers.Any(clazz);
-};
-
-/**
- * Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
- * attributes on the object.
- *
- * @example
- * // don't care about any other attributes than foo.
- * expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
- *
- * @param sample {Object} sample
- * @returns matchable object for the sample
- */
-jasmine.objectContaining = function (sample) {
-    return new jasmine.Matchers.ObjectContaining(sample);
-};
-
-/**
- * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
- *
- * Spies should be created in test setup, before expectations.  They can then be checked, using the standard Jasmine
- * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
- *
- * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
- *
- * Spies are torn down at the end of every spec.
- *
- * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
- *
- * @example
- * // a stub
- * var myStub = jasmine.createSpy('myStub');  // can be used anywhere
- *
- * // spy example
- * var foo = {
- *   not: function(bool) { return !bool; }
- * }
- *
- * // actual foo.not will not be called, execution stops
- * spyOn(foo, 'not');
-
- // foo.not spied upon, execution will continue to implementation
- * spyOn(foo, 'not').andCallThrough();
- *
- * // fake example
- * var foo = {
- *   not: function(bool) { return !bool; }
- * }
- *
- * // foo.not(val) will return val
- * spyOn(foo, 'not').andCallFake(function(value) {return value;});
- *
- * // mock example
- * foo.not(7 == 7);
- * expect(foo.not).toHaveBeenCalled();
- * expect(foo.not).toHaveBeenCalledWith(true);
- *
- * @constructor
- * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
- * @param {String} name
- */
-jasmine.Spy = function(name) {
-  /**
-   * The name of the spy, if provided.
-   */
-  this.identity = name || 'unknown';
-  /**
-   *  Is this Object a spy?
-   */
-  this.isSpy = true;
-  /**
-   * The actual function this spy stubs.
-   */
-  this.plan = function() {
-  };
-  /**
-   * Tracking of the most recent call to the spy.
-   * @example
-   * var mySpy = jasmine.createSpy('foo');
-   * mySpy(1, 2);
-   * mySpy.mostRecentCall.args = [1, 2];
-   */
-  this.mostRecentCall = {};
-
-  /**
-   * Holds arguments for each call to the spy, indexed by call count
-   * @example
-   * var mySpy = jasmine.createSpy('foo');
-   * mySpy(1, 2);
-   * mySpy(7, 8);
-   * mySpy.mostRecentCall.args = [7, 8];
-   * mySpy.argsForCall[0] = [1, 2];
-   * mySpy.argsForCall[1] = [7, 8];
-   */
-  this.argsForCall = [];
-  this.calls = [];
-};
-
-/**
- * Tells a spy to call through to the actual implemenatation.
- *
- * @example
- * var foo = {
- *   bar: function() { // do some stuff }
- * }
- *
- * // defining a spy on an existing property: foo.bar
- * spyOn(foo, 'bar').andCallThrough();
- */
-jasmine.Spy.prototype.andCallThrough = function() {
-  this.plan = this.originalValue;
-  return this;
-};
-
-/**
- * For setting the return value of a spy.
- *
- * @example
- * // defining a spy from scratch: foo() returns 'baz'
- * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
- *
- * // defining a spy on an existing property: foo.bar() returns 'baz'
- * spyOn(foo, 'bar').andReturn('baz');
- *
- * @param {Object} value
- */
-jasmine.Spy.prototype.andReturn = function(value) {
-  this.plan = function() {
-    return value;
-  };
-  return this;
-};
-
-/**
- * For throwing an exception when a spy is called.
- *
- * @example
- * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
- * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
- *
- * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
- * spyOn(foo, 'bar').andThrow('baz');
- *
- * @param {String} exceptionMsg
- */
-jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
-  this.plan = function() {
-    throw exceptionMsg;
-  };
-  return this;
-};
-
-/**
- * Calls an alternate implementation when a spy is called.
- *
- * @example
- * var baz = function() {
- *   // do some stuff, return something
- * }
- * // defining a spy from scratch: foo() calls the function baz
- * var foo = jasmine.createSpy('spy on foo').andCall(baz);
- *
- * // defining a spy on an existing property: foo.bar() calls an anonymnous function
- * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
- *
- * @param {Function} fakeFunc
- */
-jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
-  this.plan = fakeFunc;
-  return this;
-};
-
-/**
- * Resets all of a spy's the tracking variables so that it can be used again.
- *
- * @example
- * spyOn(foo, 'bar');
- *
- * foo.bar();
- *
- * expect(foo.bar.callCount).toEqual(1);
- *
- * foo.bar.reset();
- *
- * expect(foo.bar.callCount).toEqual(0);
- */
-jasmine.Spy.prototype.reset = function() {
-  this.wasCalled = false;
-  this.callCount = 0;
-  this.argsForCall = [];
-  this.calls = [];
-  this.mostRecentCall = {};
-};
-
-jasmine.createSpy = function(name) {
-
-  var spyObj = function() {
-    spyObj.wasCalled = true;
-    spyObj.callCount++;
-    var args = jasmine.util.argsToArray(arguments);
-    spyObj.mostRecentCall.object = this;
-    spyObj.mostRecentCall.args = args;
-    spyObj.argsForCall.push(args);
-    spyObj.calls.push({object: this, args: args});
-    return spyObj.plan.apply(this, arguments);
-  };
-
-  var spy = new jasmine.Spy(name);
-
-  for (var prop in spy) {
-    spyObj[prop] = spy[prop];
-  }
-
-  spyObj.reset();
-
-  return spyObj;
-};
-
-/**
- * Determines whether an object is a spy.
- *
- * @param {jasmine.Spy|Object} putativeSpy
- * @returns {Boolean}
- */
-jasmine.isSpy = function(putativeSpy) {
-  return putativeSpy && putativeSpy.isSpy;
-};
-
-/**
- * Creates a more complicated spy: an Object that has every property a function that is a spy.  Used for stubbing something
- * large in one call.
- *
- * @param {String} baseName name of spy class
- * @param {Array} methodNames array of names of methods to make spies
- */
-jasmine.createSpyObj = function(baseName, methodNames) {
-  if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
-    throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
-  }
-  var obj = {};
-  for (var i = 0; i < methodNames.length; i++) {
-    obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
-  }
-  return obj;
-};
-
-/**
- * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
- *
- * Be careful not to leave calls to <code>jasmine.log</code> in production code.
- */
-jasmine.log = function() {
-  var spec = jasmine.getEnv().currentSpec;
-  spec.log.apply(spec, arguments);
-};
-
-/**
- * Function that installs a spy on an existing object's method name.  Used within a Spec to create a spy.
- *
- * @example
- * // spy example
- * var foo = {
- *   not: function(bool) { return !bool; }
- * }
- * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
- *
- * @see jasmine.createSpy
- * @param obj
- * @param methodName
- * @returns a Jasmine spy that can be chained with all spy methods
- */
-var spyOn = function(obj, methodName) {
-  return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
-};
-if (isCommonJS) exports.spyOn = spyOn;
-
-/**
- * Creates a Jasmine spec that will be added to the current suite.
- *
- * // TODO: pending tests
- *
- * @example
- * it('should be true', function() {
- *   expect(true).toEqual(true);
- * });
- *
- * @param {String} desc description of this specification
- * @param {Function} func defines the preconditions and expectations of the spec
- */
-var it = function(desc, func) {
-  return jasmine.getEnv().it(desc, func);
-};
-if (isCommonJS) exports.it = it;
-
-/**
- * Creates a <em>disabled</em> Jasmine spec.
- *
- * A convenience method that allows existing specs to be disabled temporarily during development.
- *
- * @param {String} desc description of this specification
- * @param {Function} func defines the preconditions and expectations of the spec
- */
-var xit = function(desc, func) {
-  return jasmine.getEnv().xit(desc, func);
-};
-if (isCommonJS) exports.xit = xit;
-
-/**
- * Starts a chain for a Jasmine expectation.
- *
- * It is passed an Object that is the actual value and should chain to one of the many
- * jasmine.Matchers functions.
- *
- * @param {Object} actual Actual value to test against and expected value
- */
-var expect = function(actual) {
-  return jasmine.getEnv().currentSpec.expect(actual);
-};
-if (isCommonJS) exports.expect = expect;
-
-/**
- * Defines part of a jasmine spec.  Used in cominbination with waits or waitsFor in asynchrnous specs.
- *
- * @param {Function} func Function that defines part of a jasmine spec.
- */
-var runs = function(func) {
-  jasmine.getEnv().currentSpec.runs(func);
-};
-if (isCommonJS) exports.runs = runs;
-
-/**
- * Waits a fixed time period before moving to the next block.
- *
- * @deprecated Use waitsFor() instead
- * @param {Number} timeout milliseconds to wait
- */
-var waits = function(timeout) {
-  jasmine.getEnv().currentSpec.waits(timeout);
-};
-if (isCommonJS) exports.waits = waits;
-
-/**
- * Waits for the latchFunction to return true before proceeding to the next block.
- *
- * @param {Function} latchFunction
- * @param {String} optional_timeoutMessage
- * @param {Number} optional_timeout
- */
-var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
-  jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
-};
-if (isCommonJS) exports.waitsFor = waitsFor;
-
-/**
- * A function that is called before each spec in a suite.
- *
- * Used for spec setup, including validating assumptions.
- *
- * @param {Function} beforeEachFunction
- */
-var beforeEach = function(beforeEachFunction) {
-  jasmine.getEnv().beforeEach(beforeEachFunction);
-};
-if (isCommonJS) exports.beforeEach = beforeEach;
-
-/**
- * A function that is called after each spec in a suite.
- *
- * Used for restoring any state that is hijacked during spec execution.
- *
- * @param {Function} afterEachFunction
- */
-var afterEach = function(afterEachFunction) {
-  jasmine.getEnv().afterEach(afterEachFunction);
-};
-if (isCommonJS) exports.afterEach = afterEach;
-
-/**
- * Defines a suite of specifications.
- *
- * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
- * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
- * of setup in some tests.
- *
- * @example
- * // TODO: a simple suite
- *
- * // TODO: a simple suite with a nested describe block
- *
- * @param {String} description A string, usually the class under test.
- * @param {Function} specDefinitions function that defines several specs.
- */
-var describe = function(description, specDefinitions) {
-  return jasmine.getEnv().describe(description, specDefinitions);
-};
-if (isCommonJS) exports.describe = describe;
-
-/**
- * Disables a suite of specifications.  Used to disable some suites in a file, or files, temporarily during development.
- *
- * @param {String} description A string, usually the class under test.
- * @param {Function} specDefinitions function that defines several specs.
- */
-var xdescribe = function(description, specDefinitions) {
-  return jasmine.getEnv().xdescribe(description, specDefinitions);
-};
-if (isCommonJS) exports.xdescribe = xdescribe;
-
-
-// Provide the XMLHttpRequest class for IE 5.x-6.x:
-jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
-  function tryIt(f) {
-    try {
-      return f();
-    } catch(e) {
-    }
-    return null;
-  }
-
-  var xhr = tryIt(function() {
-    return new ActiveXObject("Msxml2.XMLHTTP.6.0");
-  }) ||
-    tryIt(function() {
-      return new ActiveXObject("Msxml2.XMLHTTP.3.0");
-    }) ||
-    tryIt(function() {
-      return new ActiveXObject("Msxml2.XMLHTTP");
-    }) ||
-    tryIt(function() {
-      return new ActiveXObject("Microsoft.XMLHTTP");
-    });
-
-  if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
-
-  return xhr;
-} : XMLHttpRequest;
-/**
- * @namespace
- */
-jasmine.util = {};
-
-/**
- * Declare that a child class inherit it's prototype from the parent class.
- *
- * @private
- * @param {Function} childClass
- * @param {Function} parentClass
- */
-jasmine.util.inherit = function(childClass, parentClass) {
-  /**
-   * @private
-   */
-  var subclass = function() {
-  };
-  subclass.prototype = parentClass.prototype;
-  childClass.prototype = new subclass();
-};
-
-jasmine.util.formatException = function(e) {
-  var lineNumber;
-  if (e.line) {
-    lineNumber = e.line;
-  }
-  else if (e.lineNumber) {
-    lineNumber = e.lineNumber;
-  }
-
-  var file;
-
-  if (e.sourceURL) {
-    file = e.sourceURL;
-  }
-  else if (e.fileName) {
-    file = e.fileName;
-  }
-
-  var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
-
-  if (file && lineNumber) {
-    message += ' in ' + file + ' (line ' + lineNumber + ')';
-  }
-
-  return message;
-};
-
-jasmine.util.htmlEscape = function(str) {
-  if (!str) return str;
-  return str.replace(/&/g, '&amp;')
-    .replace(/</g, '&lt;')
-    .replace(/>/g, '&gt;');
-};
-
-jasmine.util.argsToArray = function(args) {
-  var arrayOfArgs = [];
-  for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
-  return arrayOfArgs;
-};
-
-jasmine.util.extend = function(destination, source) {
-  for (var property in source) destination[property] = source[property];
-  return destination;
-};
-
-/**
- * Environment for Jasmine
- *
- * @constructor
- */
-jasmine.Env = function() {
-  this.currentSpec = null;
-  this.currentSuite = null;
-  this.currentRunner_ = new jasmine.Runner(this);
-
-  this.reporter = new jasmine.MultiReporter();
-
-  this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
-  this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
-  this.lastUpdate = 0;
-  this.specFilter = function() {
-    return true;
-  };
-
-  this.nextSpecId_ = 0;
-  this.nextSuiteId_ = 0;
-  this.equalityTesters_ = [];
-
-  // wrap matchers
-  this.matchersClass = function() {
-    jasmine.Matchers.apply(this, arguments);
-  };
-  jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
-
-  jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
-};
-
-
-jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
-jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
-jasmine.Env.prototype.setInterval = jasmine.setInterval;
-jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
-
-/**
- * @returns an object containing jasmine version build info, if set.
- */
-jasmine.Env.prototype.version = function () {
-  if (jasmine.version_) {
-    return jasmine.version_;
-  } else {
-    throw new Error('Version not set');
-  }
-};
-
-/**
- * @returns string containing jasmine version build info, if set.
- */
-jasmine.Env.prototype.versionString = function() {
-  if (!jasmine.version_) {
-    return "version unknown";
-  }
-
-  var version = this.version();
-  var versionString = version.major + "." + version.minor + "." + version.build;
-  if (version.release_candidate) {
-    versionString += ".rc" + version.release_candidate;
-  }
-  versionString += " revision " + version.revision;
-  return versionString;
-};
-
-/**
- * @returns a sequential integer starting at 0
- */
-jasmine.Env.prototype.nextSpecId = function () {
-  return this.nextSpecId_++;
-};
-
-/**
- * @returns a sequential integer starting at 0
- */
-jasmine.Env.prototype.nextSuiteId = function () {
-  return this.nextSuiteId_++;
-};
-
-/**
- * Register a reporter to receive status updates from Jasmine.
- * @param {jasmine.Reporter} reporter An object which will receive status updates.
- */
-jasmine.Env.prototype.addReporter = function(reporter) {
-  this.reporter.addReporter(reporter);
-};
-
-jasmine.Env.prototype.execute = function() {
-  this.currentRunner_.execute();
-};
-
-jasmine.Env.prototype.describe = function(description, specDefinitions) {
-  var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
-
-  var parentSuite = this.currentSuite;
-  if (parentSuite) {
-    parentSuite.add(suite);
-  } else {
-    this.currentRunner_.add(suite);
-  }
-
-  this.currentSuite = suite;
-
-  var declarationError = null;
-  try {
-    specDefinitions.call(suite);
-  } catch(e) {
-    declarationError = e;
-  }
-
-  if (declarationError) {
-    this.it("encountered a declaration exception", function() {
-      throw declarationError;
-    });
-  }
-
-  this.currentSuite = parentSuite;
-
-  return suite;
-};
-
-jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
-  if (this.currentSuite) {
-    this.currentSuite.beforeEach(beforeEachFunction);
-  } else {
-    this.currentRunner_.beforeEach(beforeEachFunction);
-  }
-};
-
-jasmine.Env.prototype.currentRunner = function () {
-  return this.currentRunner_;
-};
-
-jasmine.Env.prototype.afterEach = function(afterEachFunction) {
-  if (this.currentSuite) {
-    this.currentSuite.afterEach(afterEachFunction);
-  } else {
-    this.currentRunner_.afterEach(afterEachFunction);
-  }
-
-};
-
-jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
-  return {
-    execute: function() {
-    }
-  };
-};
-
-jasmine.Env.prototype.it = function(description, func) {
-  var spec = new jasmine.Spec(this, this.currentSuite, description);
-  this.currentSuite.add(spec);
-  this.currentSpec = spec;
-
-  if (func) {
-    spec.runs(func);
-  }
-
-  return spec;
-};
-
-jasmine.Env.prototype.xit = function(desc, func) {
-  return {
-    id: this.nextSpecId(),
-    runs: function() {
-    }
-  };
-};
-
-jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
-  if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
-    return true;
-  }
-
-  a.__Jasmine_been_here_before__ = b;
-  b.__Jasmine_been_here_before__ = a;
-
-  var hasKey = function(obj, keyName) {
-    return obj !== null && obj[keyName] !== jasmine.undefined;
-  };
-
-  for (var property in b) {
-    if (!hasKey(a, property) && hasKey(b, property)) {
-      mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
-    }
-  }
-  for (property in a) {
-    if (!hasKey(b, property) && hasKey(a, property)) {
-      mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
-    }
-  }
-  for (property in b) {
-    if (property == '__Jasmine_been_here_before__') continue;
-    if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
-      mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
-    }
-  }
-
-  if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
-    mismatchValues.push("arrays were not the same length");
-  }
-
-  delete a.__Jasmine_been_here_before__;
-  delete b.__Jasmine_been_here_before__;
-  return (mismatchKeys.length === 0 && mismatchValues.length === 0);
-};
-
-jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
-  mismatchKeys = mismatchKeys || [];
-  mismatchValues = mismatchValues || [];
-
-  for (var i = 0; i < this.equalityTesters_.length; i++) {
-    var equalityTester = this.equalityTesters_[i];
-    var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
-    if (result !== jasmine.undefined) return result;
-  }
-
-  if (a === b) return true;
-
-  if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
-    return (a == jasmine.undefined && b == jasmine.undefined);
-  }
-
-  if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
-    return a === b;
-  }
-
-  if (a instanceof Date && b instanceof Date) {
-    return a.getTime() == b.getTime();
-  }
-
-  if (a.jasmineMatches) {
-    return a.jasmineMatches(b);
-  }
-
-  if (b.jasmineMatches) {
-    return b.jasmineMatches(a);
-  }
-
-  if (a instanceof jasmine.Matchers.ObjectContaining) {
-    return a.matches(b);
-  }
-
-  if (b instanceof jasmine.Matchers.ObjectContaining) {
-    return b.matches(a);
-  }
-
-  if (jasmine.isString_(a) && jasmine.isString_(b)) {
-    return (a == b);
-  }
-
-  if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
-    return (a == b);
-  }
-
-  if (typeof a === "object" && typeof b === "object") {
-    return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
-  }
-
-  //Straight check
-  return (a === b);
-};
-
-jasmine.Env.prototype.contains_ = function(haystack, needle) {
-  if (jasmine.isArray_(haystack)) {
-    for (var i = 0; i < haystack.length; i++) {
-      if (this.equals_(haystack[i], needle)) return true;
-    }
-    return false;
-  }
-  return haystack.indexOf(needle) >= 0;
-};
-
-jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
-  this.equalityTesters_.push(equalityTester);
-};
-/** No-op base class for Jasmine reporters.
- *
- * @constructor
- */
-jasmine.Reporter = function() {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.reportSpecResults = function(spec) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.Reporter.prototype.log = function(str) {
-};
-
-/**
- * Blocks are functions with executable code that make up a spec.
- *
- * @constructor
- * @param {jasmine.Env} env
- * @param {Function} func
- * @param {jasmine.Spec} spec
- */
-jasmine.Block = function(env, func, spec) {
-  this.env = env;
-  this.func = func;
-  this.spec = spec;
-};
-
-jasmine.Block.prototype.execute = function(onComplete) {  
-  try {
-    this.func.apply(this.spec);
-  } catch (e) {
-    this.spec.fail(e);
-  }
-  onComplete();
-};
-/** JavaScript API reporter.
- *
- * @constructor
- */
-jasmine.JsApiReporter = function() {
-  this.started = false;
-  this.finished = false;
-  this.suites_ = [];
-  this.results_ = {};
-};
-
-jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
-  this.started = true;
-  var suites = runner.topLevelSuites();
-  for (var i = 0; i < suites.length; i++) {
-    var suite = suites[i];
-    this.suites_.push(this.summarize_(suite));
-  }
-};
-
-jasmine.JsApiReporter.prototype.suites = function() {
-  return this.suites_;
-};
-
-jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
-  var isSuite = suiteOrSpec instanceof jasmine.Suite;
-  var summary = {
-    id: suiteOrSpec.id,
-    name: suiteOrSpec.description,
-    type: isSuite ? 'suite' : 'spec',
-    children: []
-  };
-  
-  if (isSuite) {
-    var children = suiteOrSpec.children();
-    for (var i = 0; i < children.length; i++) {
-      summary.children.push(this.summarize_(children[i]));
-    }
-  }
-  return summary;
-};
-
-jasmine.JsApiReporter.prototype.results = function() {
-  return this.results_;
-};
-
-jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
-  return this.results_[specId];
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
-  this.finished = true;
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
-  this.results_[spec.id] = {
-    messages: spec.results().getItems(),
-    result: spec.results().failedCount > 0 ? "failed" : "passed"
-  };
-};
-
-//noinspection JSUnusedLocalSymbols
-jasmine.JsApiReporter.prototype.log = function(str) {
-};
-
-jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
-  var results = {};
-  for (var i = 0; i < specIds.length; i++) {
-    var specId = specIds[i];
-    results[specId] = this.summarizeResult_(this.results_[specId]);
-  }
-  return results;
-};
-
-jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
-  var summaryMessages = [];
-  var messagesLength = result.messages.length;
-  for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
-    var resultMessage = result.messages[messageIndex];
-    summaryMessages.push({
-      text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
-      passed: resultMessage.passed ? resultMessage.passed() : true,
-      type: resultMessage.type,
-      message: resultMessage.message,
-      trace: {
-        stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
-      }
-    });
-  }
-
-  return {
-    result : result.result,
-    messages : summaryMessages
-  };
-};
-
-/**
- * @constructor
- * @param {jasmine.Env} env
- * @param actual
- * @param {jasmine.Spec} spec
- */
-jasmine.Matchers = function(env, actual, spec, opt_isNot) {
-  this.env = env;
-  this.actual = actual;
-  this.spec = spec;
-  this.isNot = opt_isNot || false;
-  this.reportWasCalled_ = false;
-};
-
-// todo: @deprecated as of Jasmine 0.11, remove soon [xw]
-jasmine.Matchers.pp = function(str) {
-  throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
-};
-
-// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
-jasmine.Matchers.prototype.report = function(result, failing_message, details) {
-  throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
-};
-
-jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
-  for (var methodName in prototype) {
-    if (methodName == 'report') continue;
-    var orig = prototype[methodName];
-    matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
-  }
-};
-
-jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
-  return function() {
-    var matcherArgs = jasmine.util.argsToArray(arguments);
-    var result = matcherFunction.apply(this, arguments);
-
-    if (this.isNot) {
-      result = !result;
-    }
-
-    if (this.reportWasCalled_) return result;
-
-    var message;
-    if (!result) {
-      if (this.message) {
-        message = this.message.apply(this, arguments);
-        if (jasmine.isArray_(message)) {
-          message = message[this.isNot ? 1 : 0];
-        }
-      } else {
-        var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
-        message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
-        if (matcherArgs.length > 0) {
-          for (var i = 0; i < matcherArgs.length; i++) {
-            if (i > 0) message += ",";
-            message += " " + jasmine.pp(matcherArgs[i]);
-          }
-        }
-        message += ".";
-      }
-    }
-    var expectationResult = new jasmine.ExpectationResult({
-      matcherName: matcherName,
-      passed: result,
-      expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
-      actual: this.actual,
-      message: message
-    });
-    this.spec.addMatcherResult(expectationResult);
-    return jasmine.undefined;
-  };
-};
-
-
-
-
-/**
- * toBe: compares the actual to the expected using ===
- * @param expected
- */
-jasmine.Matchers.prototype.toBe = function(expected) {
-  return this.actual === expected;
-};
-
-/**
- * toNotBe: compares the actual to the expected using !==
- * @param expected
- * @deprecated as of 1.0. Use not.toBe() instead.
- */
-jasmine.Matchers.prototype.toNotBe = function(expected) {
-  return this.actual !== expected;
-};
-
-/**
- * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
- *
- * @param expected
- */
-jasmine.Matchers.prototype.toEqual = function(expected) {
-  return this.env.equals_(this.actual, expected);
-};
-
-/**
- * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
- * @param expected
- * @deprecated as of 1.0. Use not.toEqual() instead.
- */
-jasmine.Matchers.prototype.toNotEqual = function(expected) {
-  return !this.env.equals_(this.actual, expected);
-};
-
-/**
- * Matcher that compares the actual to the expected using a regular expression.  Constructs a RegExp, so takes
- * a pattern or a String.
- *
- * @param expected
- */
-jasmine.Matchers.prototype.toMatch = function(expected) {
-  return new RegExp(expected).test(this.actual);
-};
-
-/**
- * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
- * @param expected
- * @deprecated as of 1.0. Use not.toMatch() instead.
- */
-jasmine.Matchers.prototype.toNotMatch = function(expected) {
-  return !(new RegExp(expected).test(this.actual));
-};
-
-/**
- * Matcher that compares the actual to jasmine.undefined.
- */
-jasmine.Matchers.prototype.toBeDefined = function() {
-  return (this.actual !== jasmine.undefined);
-};
-
-/**
- * Matcher that compares the actual to jasmine.undefined.
- */
-jasmine.Matchers.prototype.toBeUndefined = function() {
-  return (this.actual === jasmine.undefined);
-};
-
-/**
- * Matcher that compares the actual to null.
- */
-jasmine.Matchers.prototype.toBeNull = function() {
-  return (this.actual === null);
-};
-
-/**
- * Matcher that boolean not-nots the actual.
- */
-jasmine.Matchers.prototype.toBeTruthy = function() {
-  return !!this.actual;
-};
-
-
-/**
- * Matcher that boolean nots the actual.
- */
-jasmine.Matchers.prototype.toBeFalsy = function() {
-  return !this.actual;
-};
-
-
-/**
- * Matcher that checks to see if the actual, a Jasmine spy, was called.
- */
-jasmine.Matchers.prototype.toHaveBeenCalled = function() {
-  if (arguments.length > 0) {
-    throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
-  }
-
-  if (!jasmine.isSpy(this.actual)) {
-    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
-  }
-
-  this.message = function() {
-    return [
-      "Expected spy " + this.actual.identity + " to have been called.",
-      "Expected spy " + this.actual.identity + " not to have been called."
-    ];
-  };
-
-  return this.actual.wasCalled;
-};
-
-/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
-jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
-
-/**
- * Matcher that checks to see if the actual, a Jasmine spy, was not called.
- *
- * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
- */
-jasmine.Matchers.prototype.wasNotCalled = function() {
-  if (arguments.length > 0) {
-    throw new Error('wasNotCalled does not take arguments');
-  }
-
-  if (!jasmine.isSpy(this.actual)) {
-    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
-  }
-
-  this.message = function() {
-    return [
-      "Expected spy " + this.actual.identity + " to not have been called.",
-      "Expected spy " + this.actual.identity + " to have been called."
-    ];
-  };
-
-  return !this.actual.wasCalled;
-};
-
-/**
- * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
- *
- * @example
- *
- */
-jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
-  var expectedArgs = jasmine.util.argsToArray(arguments);
-  if (!jasmine.isSpy(this.actual)) {
-    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
-  }
-  this.message = function() {
-    if (this.actual.callCount === 0) {
-      // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw]
-      return [
-        "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.",
-        "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."
-      ];
-    } else {
-      return [
-        "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall),
-        "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but was called with " + jasmine.pp(this.actual.argsForCall)
-      ];
-    }
-  };
-
-  return this.env.contains_(this.actual.argsForCall, expectedArgs);
-};
-
-/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
-jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
-
-/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
-jasmine.Matchers.prototype.wasNotCalledWith = function() {
-  var expectedArgs = jasmine.util.argsToArray(arguments);
-  if (!jasmine.isSpy(this.actual)) {
-    throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
-  }
-
-  this.message = function() {
-    return [
-      "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
-      "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
-    ];
-  };
-
-  return !this.env.contains_(this.actual.argsForCall, expectedArgs);
-};
-
-/**
- * Matcher that checks that the expected item is an element in the actual Array.
- *
- * @param {Object} expected
- */
-jasmine.Matchers.prototype.toContain = function(expected) {
-  return this.env.contains_(this.actual, expected);
-};
-
-/**
- * Matcher that checks that the expected item is NOT an element in the actual Array.
- *
- * @param {Object} expected
- * @deprecated as of 1.0. Use not.toContain() instead.
- */
-jasmine.Matchers.prototype.toNotContain = function(expected) {
-  return !this.env.contains_(this.actual, expected);
-};
-
-jasmine.Matchers.prototype.toBeLessThan = function(expected) {
-  return this.actual < expected;
-};
-
-jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
-  return this.actual > expected;
-};
-
-/**
- * Matcher that checks that the expected item is equal to the actual item
- * up to a given level of decimal precision (default 2).
- *
- * @param {Number} expected
- * @param {Number} precision
- */
-jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
-  if (!(precision === 0)) {
-    precision = precision || 2;
-  }
-  var multiplier = Math.pow(10, precision);
-  var actual = Math.round(this.actual * multiplier);
-  expected = Math.round(expected * multiplier);
-  return expected == actual;
-};
-
-/**
- * Matcher that checks that the expected exception was thrown by the actual.
- *
- * @param {String} expected
- */
-jasmine.Matchers.prototype.toThrow = function(expected) {
-  var result = false;
-  var exception;
-  if (typeof this.actual != 'function') {
-    throw new Error('Actual is not a function');
-  }
-  try {
-    this.actual();
-  } catch (e) {
-    exception = e;
-  }
-  if (exception) {
-    result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
-  }
-
-  var not = this.isNot ? "not " : "";
-
-  this.message = function() {
-    if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
-      return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
-    } else {
-      return "Expected function to throw an exception.";
-    }
-  };
-
-  return result;
-};
-
-jasmine.Matchers.Any = function(expectedClass) {
-  this.expectedClass = expectedClass;
-};
-
-jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
-  if (this.expectedClass == String) {
-    return typeof other == 'string' || other instanceof String;
-  }
-
-  if (this.expectedClass == Number) {
-    return typeof other == 'number' || other instanceof Number;
-  }
-
-  if (this.expectedClass == Function) {
-    return typeof other == 'function' || other instanceof Function;
-  }
-
-  if (this.expectedClass == Object) {
-    return typeof other == 'object';
-  }
-
-  return other instanceof this.expectedClass;
-};
-
-jasmine.Matchers.Any.prototype.jasmineToString = function() {
-  return '<jasmine.any(' + this.expectedClass + ')>';
-};
-
-jasmine.Matchers.ObjectContaining = function (sample) {
-  this.sample = sample;
-};
-
-jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
-  mismatchKeys = mismatchKeys || [];
-  mismatchValues = mismatchValues || [];
-
-  var env = jasmine.getEnv();
-
-  var hasKey = function(obj, keyName) {
-    return obj != null && obj[keyName] !== jasmine.undefined;
-  };
-
-  for (var property in this.sample) {
-    if (!hasKey(other, property) && hasKey(this.sample, property)) {
-      mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
-    }
-    else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
-      mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
-    }
-  }
-
-  return (mismatchKeys.length === 0 && mismatchValues.length === 0);
-};
-
-jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
-  return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
-};
-// Mock setTimeout, clearTimeout
-// Contributed by Pivotal Computer Systems, www.pivotalsf.com
-
-jasmine.FakeTimer = function() {
-  this.reset();
-
-  var self = this;
-  self.setTimeout = function(funcToCall, millis) {
-    self.timeoutsMade++;
-    self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
-    return self.timeoutsMade;
-  };
-
-  self.setInterval = function(funcToCall, millis) {
-    self.timeoutsMade++;
-    self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
-    return self.timeoutsMade;
-  };
-
-  self.clearTimeout = function(timeoutKey) {
-    self.scheduledFunctions[timeoutKey] = jasmine.undefined;
-  };
-
-  self.clearInterval = function(timeoutKey) {
-    self.scheduledFunctions[timeoutKey] = jasmine.undefined;
-  };
-
-};
-
-jasmine.FakeTimer.prototype.reset = function() {
-  this.timeoutsMade = 0;
-  this.scheduledFunctions = {};
-  this.nowMillis = 0;
-};
-
-jasmine.FakeTimer.prototype.tick = function(millis) {
-  var oldMillis = this.nowMillis;
-  var newMillis = oldMillis + millis;
-  this.runFunctionsWithinRange(oldMillis, newMillis);
-  this.nowMillis = newMillis;
-};
-
-jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
-  var scheduledFunc;
-  var funcsToRun = [];
-  for (var timeoutKey in this.scheduledFunctions) {
-    scheduledFunc = this.scheduledFunctions[timeoutKey];
-    if (scheduledFunc != jasmine.undefined &&
-        scheduledFunc.runAtMillis >= oldMillis &&
-        scheduledFunc.runAtMillis <= nowMillis) {
-      funcsToRun.push(scheduledFunc);
-      this.scheduledFunctions[timeoutKey] = jasmine.undefined;
-    }
-  }
-
-  if (funcsToRun.length > 0) {
-    funcsToRun.sort(function(a, b) {
-      return a.runAtMillis - b.runAtMillis;
-    });
-    for (var i = 0; i < funcsToRun.length; ++i) {
-      try {
-        var funcToRun = funcsToRun[i];
-        this.nowMillis = funcToRun.runAtMillis;
-        funcToRun.funcToCall();
-        if (funcToRun.recurring) {
-          this.scheduleFunction(funcToRun.timeoutKey,
-              funcToRun.funcToCall,
-              funcToRun.millis,
-              true);
-        }
-      } catch(e) {
-      }
-    }
-    this.runFunctionsWithinRange(oldMillis, nowMillis);
-  }
-};
-
-jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
-  this.scheduledFunctions[timeoutKey] = {
-    runAtMillis: this.nowMillis + millis,
-    funcToCall: funcToCall,
-    recurring: recurring,
-    timeoutKey: timeoutKey,
-    millis: millis
-  };
-};
-
-/**
- * @namespace
- */
-jasmine.Clock = {
-  defaultFakeTimer: new jasmine.FakeTimer(),
-
-  reset: function() {
-    jasmine.Clock.assertInstalled();
-    jasmine.Clock.defaultFakeTimer.reset();
-  },
-
-  tick: function(millis) {
-    jasmine.Clock.assertInstalled();
-    jasmine.Clock.defaultFakeTimer.tick(millis);
-  },
-
-  runFunctionsWithinRange: function(oldMillis, nowMillis) {
-    jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
-  },
-
-  scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
-    jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
-  },
-
-  useMock: function() {
-    if (!jasmine.Clock.isInstalled()) {
-      var spec = jasmine.getEnv().currentSpec;
-      spec.after(jasmine.Clock.uninstallMock);
-
-      jasmine.Clock.installMock();
-    }
-  },
-
-  installMock: function() {
-    jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
-  },
-
-  uninstallMock: function() {
-    jasmine.Clock.assertInstalled();
-    jasmine.Clock.installed = jasmine.Clock.real;
-  },
-
-  real: {
-    setTimeout: jasmine.getGlobal().setTimeout,
-    clearTimeout: jasmine.getGlobal().clearTimeout,
-    setInterval: jasmine.getGlobal().setInterval,
-    clearInterval: jasmine.getGlobal().clearInterval
-  },
-
-  assertInstalled: function() {
-    if (!jasmine.Clock.isInstalled()) {
-      throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
-    }
-  },
-
-  isInstalled: function() {
-    return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
-  },
-
-  installed: null
-};
-jasmine.Clock.installed = jasmine.Clock.real;
-
-//else for IE support
-jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
-  if (jasmine.Clock.installed.setTimeout.apply) {
-    return jasmine.Clock.installed.setTimeout.apply(this, arguments);
-  } else {
-    return jasmine.Clock.installed.setTimeout(funcToCall, millis);
-  }
-};
-
-jasmine.getGlobal().setInterval = function(funcToCall, millis) {
-  if (jasmine.Clock.installed.setInterval.apply) {
-    return jasmine.Clock.installed.setInterval.apply(this, arguments);
-  } else {
-    return jasmine.Clock.installed.setInterval(funcToCall, millis);
-  }
-};
-
-jasmine.getGlobal().clearTimeout = function(timeoutKey) {
-  if (jasmine.Clock.installed.clearTimeout.apply) {
-    return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
-  } else {
-    return jasmine.Clock.installed.clearTimeout(timeoutKey);
-  }
-};
-
-jasmine.getGlobal().clearInterval = function(timeoutKey) {
-  if (jasmine.Clock.installed.clearTimeout.apply) {
-    return jasmine.Clock.installed.clearInterval.apply(this, arguments);
-  } else {
-    return jasmine.Clock.installed.clearInterval(timeoutKey);
-  }
-};
-
-/**
- * @constructor
- */
-jasmine.MultiReporter = function() {
-  this.subReporters_ = [];
-};
-jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
-
-jasmine.MultiReporter.prototype.addReporter = function(reporter) {
-  this.subReporters_.push(reporter);
-};
-
-(function() {
-  var functionNames = [
-    "reportRunnerStarting",
-    "reportRunnerResults",
-    "reportSuiteResults",
-    "reportSpecStarting",
-    "reportSpecResults",
-    "log"
-  ];
-  for (var i = 0; i < functionNames.length; i++) {
-    var functionName = functionNames[i];
-    jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
-      return function() {
-        for (var j = 0; j < this.subReporters_.length; j++) {
-          var subReporter = this.subReporters_[j];
-          if (subReporter[functionName]) {
-            subReporter[functionName].apply(subReporter, arguments);
-          }
-        }
-      };
-    })(functionName);
-  }
-})();
-/**
- * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
- *
- * @constructor
- */
-jasmine.NestedResults = function() {
-  /**
-   * The total count of results
-   */
-  this.totalCount = 0;
-  /**
-   * Number of passed results
-   */
-  this.passedCount = 0;
-  /**
-   * Number of failed results
-   */
-  this.failedCount = 0;
-  /**
-   * Was this suite/spec skipped?
-   */
-  this.skipped = false;
-  /**
-   * @ignore
-   */
-  this.items_ = [];
-};
-
-/**
- * Roll up the result counts.
- *
- * @param result
- */
-jasmine.NestedResults.prototype.rollupCounts = function(result) {
-  this.totalCount += result.totalCount;
-  this.passedCount += result.passedCount;
-  this.failedCount += result.failedCount;
-};
-
-/**
- * Adds a log message.
- * @param values Array of message parts which will be concatenated later.
- */
-jasmine.NestedResults.prototype.log = function(values) {
-  this.items_.push(new jasmine.MessageResult(values));
-};
-
-/**
- * Getter for the results: message & results.
- */
-jasmine.NestedResults.prototype.getItems = function() {
-  return this.items_;
-};
-
-/**
- * Adds a result, tracking counts (total, passed, & failed)
- * @param {jasmine.ExpectationResult|jasmine.NestedResults} result
- */
-jasmine.NestedResults.prototype.addResult = function(result) {
-  if (result.type != 'log') {
-    if (result.items_) {
-      this.rollupCounts(result);
-    } else {
-      this.totalCount++;
-      if (result.passed()) {
-        this.passedCount++;
-      } else {
-        this.failedCount++;
-      }
-    }
-  }
-  this.items_.push(result);
-};
-
-/**
- * @returns {Boolean} True if <b>everything</b> below passed
- */
-jasmine.NestedResults.prototype.passed = function() {
-  return this.passedCount === this.totalCount;
-};
-/**
- * Base class for pretty printing for expectation results.
- */
-jasmine.PrettyPrinter = function() {
-  this.ppNestLevel_ = 0;
-};
-
-/**
- * Formats a value in a nice, human-readable string.
- *
- * @param value
- */
-jasmine.PrettyPrinter.prototype.format = function(value) {
-  if (this.ppNestLevel_ > 40) {
-    throw new Error('jasmine.PrettyPrinter: format() nested too deeply!');
-  }
-
-  this.ppNestLevel_++;
-  try {
-    if (value === jasmine.undefined) {
-      this.emitScalar('undefined');
-    } else if (value === null) {
-      this.emitScalar('null');
-    } else if (value === jasmine.getGlobal()) {
-      this.emitScalar('<global>');
-    } else if (value.jasmineToString) {
-      this.emitScalar(value.jasmineToString());
-    } else if (typeof value === 'string') {
-      this.emitString(value);
-    } else if (jasmine.isSpy(value)) {
-      this.emitScalar("spy on " + value.identity);
-    } else if (value instanceof RegExp) {
-      this.emitScalar(value.toString());
-    } else if (typeof value === 'function') {
-      this.emitScalar('Function');
-    } else if (typeof value.nodeType === 'number') {
-      this.emitScalar('HTMLNode');
-    } else if (value instanceof Date) {
-      this.emitScalar('Date(' + value + ')');
-    } else if (value.__Jasmine_been_here_before__) {
-      this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
-    } else if (jasmine.isArray_(value) || typeof value == 'object') {
-      value.__Jasmine_been_here_before__ = true;
-      if (jasmine.isArray_(value)) {
-        this.emitArray(value);
-      } else {
-        this.emitObject(value);
-      }
-      delete value.__Jasmine_been_here_before__;
-    } else {
-      this.emitScalar(value.toString());
-    }
-  } finally {
-    this.ppNestLevel_--;
-  }
-};
-
-jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
-  for (var property in obj) {
-    if (property == '__Jasmine_been_here_before__') continue;
-    fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined && 
-                                         obj.__lookupGetter__(property) !== null) : false);
-  }
-};
-
-jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
-jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
-jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
-jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
-
-jasmine.StringPrettyPrinter = function() {
-  jasmine.PrettyPrinter.call(this);
-
-  this.string = '';
-};
-jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
-
-jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
-  this.append(value);
-};
-
-jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
-  this.append("'" + value + "'");
-};
-
-jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
-  this.append('[ ');
-  for (var i = 0; i < array.length; i++) {
-    if (i > 0) {
-      this.append(', ');
-    }
-    this.format(array[i]);
-  }
-  this.append(' ]');
-};
-
-jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
-  var self = this;
-  this.append('{ ');
-  var first = true;
-
-  this.iterateObject(obj, function(property, isGetter) {
-    if (first) {
-      first = false;
-    } else {
-      self.append(', ');
-    }
-
-    self.append(property);
-    self.append(' : ');
-    if (isGetter) {
-      self.append('<getter>');
-    } else {
-      self.format(obj[property]);
-    }
-  });
-
-  this.append(' }');
-};
-
-jasmine.StringPrettyPrinter.prototype.append = function(value) {
-  this.string += value;
-};
-jasmine.Queue = function(env) {
-  this.env = env;
-  this.blocks = [];
-  this.running = false;
-  this.index = 0;
-  this.offset = 0;
-  this.abort = false;
-};
-
-jasmine.Queue.prototype.addBefore = function(block) {
-  this.blocks.unshift(block);
-};
-
-jasmine.Queue.prototype.add = function(block) {
-  this.blocks.push(block);
-};
-
-jasmine.Queue.prototype.insertNext = function(block) {
-  this.blocks.splice((this.index + this.offset + 1), 0, block);
-  this.offset++;
-};
-
-jasmine.Queue.prototype.start = function(onComplete) {
-  this.running = true;
-  this.onComplete = onComplete;
-  this.next_();
-};
-
-jasmine.Queue.prototype.isRunning = function() {
-  return this.running;
-};
-
-jasmine.Queue.LOOP_DONT_RECURSE = true;
-
-jasmine.Queue.prototype.next_ = function() {
-  var self = this;
-  var goAgain = true;
-
-  while (goAgain) {
-    goAgain = false;
-    
-    if (self.index < self.blocks.length && !this.abort) {
-      var calledSynchronously = true;
-      var completedSynchronously = false;
-
-      var onComplete = function () {
-        if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
-          completedSynchronously = true;
-          return;
-        }
-
-        if (self.blocks[self.index].abort) {
-          self.abort = true;
-        }
-
-        self.offset = 0;
-        self.index++;
-
-        var now = new Date().getTime();
-        if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
-          self.env.lastUpdate = now;
-          self.env.setTimeout(function() {
-            self.next_();
-          }, 0);
-        } else {
-          if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
-            goAgain = true;
-          } else {
-            self.next_();
-          }
-        }
-      };
-      self.blocks[self.index].execute(onComplete);
-
-      calledSynchronously = false;
-      if (completedSynchronously) {
-        onComplete();
-      }
-      
-    } else {
-      self.running = false;
-      if (self.onComplete) {
-        self.onComplete();
-      }
-    }
-  }
-};
-
-jasmine.Queue.prototype.results = function() {
-  var results = new jasmine.NestedResults();
-  for (var i = 0; i < this.blocks.length; i++) {
-    if (this.blocks[i].results) {
-      results.addResult(this.blocks[i].results());
-    }
-  }
-  return results;
-};
-
-
-/**
- * Runner
- *
- * @constructor
- * @param {jasmine.Env} env
- */
-jasmine.Runner = function(env) {
-  var self = this;
-  self.env = env;
-  self.queue = new jasmine.Queue(env);
-  self.before_ = [];
-  self.after_ = [];
-  self.suites_ = [];
-};
-
-jasmine.Runner.prototype.execute = function() {
-  var self = this;
-  if (self.env.reporter.reportRunnerStarting) {
-    self.env.reporter.reportRunnerStarting(this);
-  }
-  self.queue.start(function () {
-    self.finishCallback();
-  });
-};
-
-jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
-  beforeEachFunction.typeName = 'beforeEach';
-  this.before_.splice(0,0,beforeEachFunction);
-};
-
-jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
-  afterEachFunction.typeName = 'afterEach';
-  this.after_.splice(0,0,afterEachFunction);
-};
-
-
-jasmine.Runner.prototype.finishCallback = function() {
-  this.env.reporter.reportRunnerResults(this);
-};
-
-jasmine.Runner.prototype.addSuite = function(suite) {
-  this.suites_.push(suite);
-};
-
-jasmine.Runner.prototype.add = function(block) {
-  if (block instanceof jasmine.Suite) {
-    this.addSuite(block);
-  }
-  this.queue.add(block);
-};
-
-jasmine.Runner.prototype.specs = function () {
-  var suites = this.suites();
-  var specs = [];
-  for (var i = 0; i < suites.length; i++) {
-    specs = specs.concat(suites[i].specs());
-  }
-  return specs;
-};
-
-jasmine.Runner.prototype.suites = function() {
-  return this.suites_;
-};
-
-jasmine.Runner.prototype.topLevelSuites = function() {
-  var topLevelSuites = [];
-  for (var i = 0; i < this.suites_.length; i++) {
-    if (!this.suites_[i].parentSuite) {
-      topLevelSuites.push(this.suites_[i]);
-    }
-  }
-  return topLevelSuites;
-};
-
-jasmine.Runner.prototype.results = function() {
-  return this.queue.results();
-};
-/**
- * Internal representation of a Jasmine specification, or test.
- *
- * @constructor
- * @param {jasmine.Env} env
- * @param {jasmine.Suite} suite
- * @param {String} description
- */
-jasmine.Spec = function(env, suite, description) {
-  if (!env) {
-    throw new Error('jasmine.Env() required');
-  }
-  if (!suite) {
-    throw new Error('jasmine.Suite() required');
-  }
-  var spec = this;
-  spec.id = env.nextSpecId ? env.nextSpecId() : null;
-  spec.env = env;
-  spec.suite = suite;
-  spec.description = description;
-  spec.queue = new jasmine.Queue(env);
-
-  spec.afterCallbacks = [];
-  spec.spies_ = [];
-
-  spec.results_ = new jasmine.NestedResults();
-  spec.results_.description = description;
-  spec.matchersClass = null;
-};
-
-jasmine.Spec.prototype.getFullName = function() {
-  return this.suite.getFullName() + ' ' + this.description + '.';
-};
-
-
-jasmine.Spec.prototype.results = function() {
-  return this.results_;
-};
-
-/**
- * All parameters are pretty-printed and concatenated together, then written to the spec's output.
- *
- * Be careful not to leave calls to <code>jasmine.log</code> in production code.
- */
-jasmine.Spec.prototype.log = function() {
-  return this.results_.log(arguments);
-};
-
-jasmine.Spec.prototype.runs = function (func) {
-  var block = new jasmine.Block(this.env, func, this);
-  this.addToQueue(block);
-  return this;
-};
-
-jasmine.Spec.prototype.addToQueue = function (block) {
-  if (this.queue.isRunning()) {
-    this.queue.insertNext(block);
-  } else {
-    this.queue.add(block);
-  }
-};
-
-/**
- * @param {jasmine.ExpectationResult} result
- */
-jasmine.Spec.prototype.addMatcherResult = function(result) {
-  this.results_.addResult(result);
-};
-
-jasmine.Spec.prototype.expect = function(actual) {
-  var positive = new (this.getMatchersClass_())(this.env, actual, this);
-  positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
-  return positive;
-};
-
-/**
- * Waits a fixed time period before moving to the next block.
- *
- * @deprecated Use waitsFor() instead
- * @param {Number} timeout milliseconds to wait
- */
-jasmine.Spec.prototype.waits = function(timeout) {
-  var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
-  this.addToQueue(waitsFunc);
-  return this;
-};
-
-/**
- * Waits for the latchFunction to return true before proceeding to the next block.
- *
- * @param {Function} latchFunction
- * @param {String} optional_timeoutMessage
- * @param {Number} optional_timeout
- */
-jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
-  var latchFunction_ = null;
-  var optional_timeoutMessage_ = null;
-  var optional_timeout_ = null;
-
-  for (var i = 0; i < arguments.length; i++) {
-    var arg = arguments[i];
-    switch (typeof arg) {
-      case 'function':
-        latchFunction_ = arg;
-        break;
-      case 'string':
-        optional_timeoutMessage_ = arg;
-        break;
-      case 'number':
-        optional_timeout_ = arg;
-        break;
-    }
-  }
-
-  var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
-  this.addToQueue(waitsForFunc);
-  return this;
-};
-
-jasmine.Spec.prototype.fail = function (e) {
-  var expectationResult = new jasmine.ExpectationResult({
-    passed: false,
-    message: e ? jasmine.util.formatException(e) : 'Exception',
-    trace: { stack: e.stack }
-  });
-  this.results_.addResult(expectationResult);
-};
-
-jasmine.Spec.prototype.getMatchersClass_ = function() {
-  return this.matchersClass || this.env.matchersClass;
-};
-
-jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
-  var parent = this.getMatchersClass_();
-  var newMatchersClass = function() {
-    parent.apply(this, arguments);
-  };
-  jasmine.util.inherit(newMatchersClass, parent);
-  jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
-  this.matchersClass = newMatchersClass;
-};
-
-jasmine.Spec.prototype.finishCallback = function() {
-  this.env.reporter.reportSpecResults(this);
-};
-
-jasmine.Spec.prototype.finish = function(onComplete) {
-  this.removeAllSpies();
-  this.finishCallback();
-  if (onComplete) {
-    onComplete();
-  }
-};
-
-jasmine.Spec.prototype.after = function(doAfter) {
-  if (this.queue.isRunning()) {
-    this.queue.add(new jasmine.Block(this.env, doAfter, this));
-  } else {
-    this.afterCallbacks.unshift(doAfter);
-  }
-};
-
-jasmine.Spec.prototype.execute = function(onComplete) {
-  var spec = this;
-  if (!spec.env.specFilter(spec)) {
-    spec.results_.skipped = true;
-    spec.finish(onComplete);
-    return;
-  }
-
-  this.env.reporter.reportSpecStarting(this);
-
-  spec.env.currentSpec = spec;
-
-  spec.addBeforesAndAftersToQueue();
-
-  spec.queue.start(function () {
-    spec.finish(onComplete);
-  });
-};
-
-jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
-  var runner = this.env.currentRunner();
-  var i;
-
-  for (var suite = this.suite; suite; suite = suite.parentSuite) {
-    for (i = 0; i < suite.before_.length; i++) {
-      this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
-    }
-  }
-  for (i = 0; i < runner.before_.length; i++) {
-    this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
-  }
-  for (i = 0; i < this.afterCallbacks.length; i++) {
-    this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this));
-  }
-  for (suite = this.suite; suite; suite = suite.parentSuite) {
-    for (i = 0; i < suite.after_.length; i++) {
-      this.queue.add(new jasmine.Block(this.env, suite.after_[i], this));
-    }
-  }
-  for (i = 0; i < runner.after_.length; i++) {
-    this.queue.add(new jasmine.Block(this.env, runner.after_[i], this));
-  }
-};
-
-jasmine.Spec.prototype.explodes = function() {
-  throw 'explodes function should not have been called';
-};
-
-jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
-  if (obj == jasmine.undefined) {
-    throw "spyOn could not find an object to spy upon for " + methodName + "()";
-  }
-
-  if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
-    throw methodName + '() method does not exist';
-  }
-
-  if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
-    throw new Error(methodName + ' has already been spied upon');
-  }
-
-  var spyObj = jasmine.createSpy(methodName);
-
-  this.spies_.push(spyObj);
-  spyObj.baseObj = obj;
-  spyObj.methodName = methodName;
-  spyObj.originalValue = obj[methodName];
-
-  obj[methodName] = spyObj;
-
-  return spyObj;
-};
-
-jasmine.Spec.prototype.removeAllSpies = function() {
-  for (var i = 0; i < this.spies_.length; i++) {
-    var spy = this.spies_[i];
-    spy.baseObj[spy.methodName] = spy.originalValue;
-  }
-  this.spies_ = [];
-};
-
-/**
- * Internal representation of a Jasmine suite.
- *
- * @constructor
- * @param {jasmine.Env} env
- * @param {String} description
- * @param {Function} specDefinitions
- * @param {jasmine.Suite} parentSuite
- */
-jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
-  var self = this;
-  self.id = env.nextSuiteId ? env.nextSuiteId() : null;
-  self.description = description;
-  self.queue = new jasmine.Queue(env);
-  self.parentSuite = parentSuite;
-  self.env = env;
-  self.before_ = [];
-  self.after_ = [];
-  self.children_ = [];
-  self.suites_ = [];
-  self.specs_ = [];
-};
-
-jasmine.Suite.prototype.getFullName = function() {
-  var fullName = this.description;
-  for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
-    fullName = parentSuite.description + ' ' + fullName;
-  }
-  return fullName;
-};
-
-jasmine.Suite.prototype.finish = function(onComplete) {
-  this.env.reporter.reportSuiteResults(this);
-  this.finished = true;
-  if (typeof(onComplete) == 'function') {
-    onComplete();
-  }
-};
-
-jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
-  beforeEachFunction.typeName = 'beforeEach';
-  this.before_.unshift(beforeEachFunction);
-};
-
-jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
-  afterEachFunction.typeName = 'afterEach';
-  this.after_.unshift(afterEachFunction);
-};
-
-jasmine.Suite.prototype.results = function() {
-  return this.queue.results();
-};
-
-jasmine.Suite.prototype.add = function(suiteOrSpec) {
-  this.children_.push(suiteOrSpec);
-  if (suiteOrSpec instanceof jasmine.Suite) {
-    this.suites_.push(suiteOrSpec);
-    this.env.currentRunner().addSuite(suiteOrSpec);
-  } else {
-    this.specs_.push(suiteOrSpec);
-  }
-  this.queue.add(suiteOrSpec);
-};
-
-jasmine.Suite.prototype.specs = function() {
-  return this.specs_;
-};
-
-jasmine.Suite.prototype.suites = function() {
-  return this.suites_;
-};
-
-jasmine.Suite.prototype.children = function() {
-  return this.children_;
-};
-
-jasmine.Suite.prototype.execute = function(onComplete) {
-  var self = this;
-  this.queue.start(function () {
-    self.finish(onComplete);
-  });
-};
-jasmine.WaitsBlock = function(env, timeout, spec) {
-  this.timeout = timeout;
-  jasmine.Block.call(this, env, null, spec);
-};
-
-jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
-
-jasmine.WaitsBlock.prototype.execute = function (onComplete) {
-  if (jasmine.VERBOSE) {
-    this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
-  }
-  this.env.setTimeout(function () {
-    onComplete();
-  }, this.timeout);
-};
-/**
- * A block which waits for some condition to become true, with timeout.
- *
- * @constructor
- * @extends jasmine.Block
- * @param {jasmine.Env} env The Jasmine environment.
- * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
- * @param {Function} latchFunction A function which returns true when the desired condition has been met.
- * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
- * @param {jasmine.Spec} spec The Jasmine spec.
- */
-jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
-  this.timeout = timeout || env.defaultTimeoutInterval;
-  this.latchFunction = latchFunction;
-  this.message = message;
-  this.totalTimeSpentWaitingForLatch = 0;
-  jasmine.Block.call(this, env, null, spec);
-};
-jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
-
-jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
-
-jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
-  if (jasmine.VERBOSE) {
-    this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
-  }
-  var latchFunctionResult;
-  try {
-    latchFunctionResult = this.latchFunction.apply(this.spec);
-  } catch (e) {
-    this.spec.fail(e);
-    onComplete();
-    return;
-  }
-
-  if (latchFunctionResult) {
-    onComplete();
-  } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
-    var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
-    this.spec.fail({
-      name: 'timeout',
-      message: message
-    });
-
-    this.abort = true;
-    onComplete();
-  } else {
-    this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
-    var self = this;
-    this.env.setTimeout(function() {
-      self.execute(onComplete);
-    }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
-  }
-};
-
-jasmine.version_= {
-  "major": 1,
-  "minor": 2,
-  "build": 0,
-  "revision": 1337005947
-};


[21/43] 2.6.0rc1 used for libs now. Bumped npm version to 2.6.0. added androids local.properties to gitignore.

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFile.m b/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
index d52405d..8c65270 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
@@ -52,7 +52,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
         paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
         self.appLibraryPath = [paths objectAtIndex:0];
 
-        self.appTempPath = [NSTemporaryDirectory ()stringByStandardizingPath];  // remove trailing slash from NSTemporaryDirectory()
+        self.appTempPath = [NSTemporaryDirectory()stringByStandardizingPath];   // remove trailing slash from NSTemporaryDirectory()
 
         self.persistentPath = [NSString stringWithFormat:@"/%@", [self.appDocsPath lastPathComponent]];
         self.temporaryPath = [NSString stringWithFormat:@"/%@", [self.appTempPath lastPathComponent]];
@@ -164,7 +164,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
             result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:QUOTA_EXCEEDED_ERR];
         } else {
             NSMutableDictionary* fileSystem = [NSMutableDictionary dictionaryWithCapacity:2];
-            [fileSystem setObject:(type == TEMPORARY ? kW3FileTemporary:kW3FilePersistent) forKey:@"name"];
+            [fileSystem setObject:(type == TEMPORARY ? kW3FileTemporary : kW3FilePersistent) forKey:@"name"];
             NSDictionary* dirEntry = [self getDirectoryEntry:fullPath isDirectory:YES];
             [fileSystem setObject:dirEntry forKey:@"root"];
             result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileSystem];
@@ -486,7 +486,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
         // In this case, we need to use an asynchronous method to retrieve the file.
         // Because of this, we can't just assign to `result` and send it at the end of the method.
         // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
-        ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset * asset) {
+        ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
             if (asset) {
                 // We have the asset!  Retrieve the metadata and send it off.
                 NSDate* date = [asset valueForProperty:ALAssetPropertyDate];
@@ -499,7 +499,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
             }
         };
         // TODO(maxw): Consider making this a class variable since it's the same every time.
-        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) {
+        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
             // Retrieving the asset failed for some reason.  Send the appropriate error.
             result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]];
             [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
@@ -525,7 +525,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
     } else {
         // didn't get fileAttribs
         CDVFileError errorCode = ABORT_ERR;
-        NSLog (@"error getting metadata: %@", [error localizedDescription]);
+        NSLog(@"error getting metadata: %@", [error localizedDescription]);
         if ([error code] == NSFileNoSuchFileError) {
             errorCode = NOT_FOUND_ERR;
         }
@@ -779,7 +779,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
                 // In this case, we need to use an asynchronous method to retrieve the file.
                 // Because of this, we can't just assign to `result` and send it at the end of the method.
                 // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
-                ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset * asset) {
+                ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
                     if (asset) {
                         // We have the asset!  Get the data and try to copy it over.
                         if (![fileMgr fileExistsAtPath:destRootPath]) {
@@ -796,7 +796,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
 
                         // We're good to go!  Write the file to the new destination.
                         ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
-                        Byte* buffer = (Byte*)malloc ([assetRepresentation size]);
+                        Byte* buffer = (Byte*)malloc([assetRepresentation size]);
                         NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil];
                         NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
                         [data writeToFile:newFullPath atomically:YES];
@@ -808,7 +808,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
                         [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
                     }
                 };
-                ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) {
+                ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
                     // Retrieving the asset failed for some reason.  Send the appropriate error.
                     result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]];
                     [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
@@ -953,7 +953,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
             // In this case, we need to use an asynchronous method to retrieve the file.
             // Because of this, we can't just assign to `result` and send it at the end of the method.
             // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
-            ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset * asset) {
+            ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
                 if (asset) {
                     // We have the asset!  Populate the dictionary and send it off.
                     NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
@@ -975,7 +975,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
                     [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
                 }
             };
-            ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) {
+            ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
                 // Retrieving the asset failed for some reason.  Send the appropriate error.
                 result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]];
                 [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
@@ -1053,154 +1053,181 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
     [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
 }
 
+- (void)readFileWithPath:(NSString*)path start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString* mimeType, CDVFileError))callback
+{
+    if (path == nil) {
+        callback(nil, nil, SYNTAX_ERR);
+    } else {
+        [self.commandDelegate runInBackground:^ {
+            if ([path hasPrefix:kCDVAssetsLibraryPrefix]) {
+                // In this case, we need to use an asynchronous method to retrieve the file.
+                // Because of this, we can't just assign to `result` and send it at the end of the method.
+                // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
+                ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
+                    if (asset) {
+                        // We have the asset!  Get the data and send it off.
+                        ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
+                        Byte* buffer = (Byte*)malloc([assetRepresentation size]);
+                        NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil];
+                        NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
+                        NSString* MIMEType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)[assetRepresentation UTI], kUTTagClassMIMEType);
+
+                        callback(data, MIMEType, NO_ERROR);
+                    } else {
+                        callback(nil, nil, NOT_FOUND_ERR);
+                    }
+                };
+                ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
+                    // Retrieving the asset failed for some reason.  Send the appropriate error.
+                    NSLog(@"Error: %@", error);
+                    callback(nil, nil, SECURITY_ERR);
+                };
+
+                ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
+                [assetsLibrary assetForURL:[NSURL URLWithString:path] resultBlock:resultBlock failureBlock:failureBlock];
+            } else {
+                NSString* mimeType = [self getMimeTypeFromPath:path];
+                if (mimeType == nil) {
+                    mimeType = @"*/*";
+                }
+                NSFileHandle* file = [NSFileHandle fileHandleForReadingAtPath:path];
+                if (start > 0) {
+                    [file seekToFileOffset:start];
+                }
+
+                NSData* readData;
+                if (end < 0) {
+                    readData = [file readDataToEndOfFile];
+                } else {
+                    readData = [file readDataOfLength:(end - start)];
+                }
+
+                [file closeFile];
+
+                callback(readData, mimeType, readData != nil ? NO_ERROR : NOT_FOUND_ERR);
+            }
+        }];
+    }
+}
+
 /* read and return file data
  * IN:
  * NSArray* arguments
  *	0 - NSString* fullPath
- *	1 - NSString* encoding - NOT USED,  iOS reads and writes using UTF8!
- *	2 - NSString* start - OPTIONAL, only provided when not == 0.
- *	3 - NSString* end - OPTIONAL, only provided when not == length.
+ *	1 - NSString* encoding
+ *	2 - NSString* start
+ *	3 - NSString* end
  */
 - (void)readAsText:(CDVInvokedUrlCommand*)command
 {
     // arguments
-    NSString* argPath = [command.arguments objectAtIndex:0];
-    NSInteger start = 0;
-    NSInteger end = -1;
-
-    if ([command.arguments count] >= 3) {
-        start = [[command.arguments objectAtIndex:2] integerValue];
-    }
-    if ([command.arguments count] >= 4) {
-        end = [[command.arguments objectAtIndex:3] integerValue];
+    NSString* path = [command argumentAtIndex:0];
+    NSString* encoding = [command argumentAtIndex:1];
+    NSInteger start = [[command argumentAtIndex:2] integerValue];
+    NSInteger end = [[command argumentAtIndex:3] integerValue];
+
+    // TODO: implement
+    if (![@"UTF-8" isEqualToString : encoding]) {
+        NSLog(@"Only UTF-8 encodings are currently supported by readAsText");
+        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:ENCODING_ERR];
+        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+        return;
     }
 
-    // NSString* encoding = [command.arguments objectAtIndex:2];   // not currently used
-    CDVPluginResult* result = nil;
-
-    NSFileHandle* file = [NSFileHandle fileHandleForReadingAtPath:argPath];
-
-    if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) {
-        // can't read assets-library URLs as text
-        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_READABLE_ERR];
-    } else if (!file) {
-        // invalid path entry
-        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
-    } else {
-        if (start > 0) {
-            [file seekToFileOffset:start];
-        }
-
-        NSData* readData;
-        if (end < 0) {
-            readData = [file readDataToEndOfFile];
-        } else {
-            readData = [file readDataOfLength:(end - start)];
+    [self readFileWithPath:path start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) {
+        CDVPluginResult* result = nil;
+        if (data != nil) {
+            NSString* str = [[NSString alloc] initWithBytesNoCopy:(void*)[data bytes] length:[data length] encoding:NSUTF8StringEncoding freeWhenDone:NO];
+            // Check that UTF8 conversion did not fail.
+            if (str != nil) {
+                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:str];
+                result.associatedObject = data;
+            } else {
+                errorCode = ENCODING_ERR;
+            }
         }
-
-        [file closeFile];
-        NSString* pNStrBuff = nil;
-        if (readData) {
-            pNStrBuff = [[NSString alloc] initWithBytes:[readData bytes] length:[readData length] encoding:NSUTF8StringEncoding];
-        } else {
-            // return empty string if no data
-            pNStrBuff = @"";
+        if (result == nil) {
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
         }
 
-        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:pNStrBuff];
-    }
-    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+    }];
 }
 
 /* Read content of text file and return as base64 encoded data url.
  * IN:
  * NSArray* arguments
  *	0 - NSString* fullPath
+ *	1 - NSString* start
+ *	2 - NSString* end
  *
  * Determines the mime type from the file extension, returns ENCODING_ERR if mimetype can not be determined.
  */
 
 - (void)readAsDataURL:(CDVInvokedUrlCommand*)command
 {
-    // arguments
-    NSString* argPath = [command.arguments objectAtIndex:0];
-    NSInteger start = 0;
-    NSInteger end = -1;
-
-    if ([command.arguments count] >= 2) {
-        start = [[command.arguments objectAtIndex:1] integerValue];
-    }
-    if ([command.arguments count] >= 3) {
-        end = [[command.arguments objectAtIndex:2] integerValue];
-    }
+    NSString* path = [command argumentAtIndex:0];
+    NSInteger start = [[command argumentAtIndex:1] integerValue];
+    NSInteger end = [[command argumentAtIndex:2] integerValue];
+
+    [self readFileWithPath:path start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) {
+        CDVPluginResult* result = nil;
+        if (data != nil) {
+            // TODO: Would be faster to base64 encode directly to the final string.
+            NSString* output = [NSString stringWithFormat:@"data:%@;base64,%@", mimeType, [data base64EncodedString]];
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:output];
+        } else {
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
+        }
 
-    CDVFileError errCode = ABORT_ERR;
-    __block CDVPluginResult* result = nil;
+        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+    }];
+}
 
-    if (!argPath) {
-        errCode = SYNTAX_ERR;
-    } else if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) {
-        // In this case, we need to use an asynchronous method to retrieve the file.
-        // Because of this, we can't just assign to `result` and send it at the end of the method.
-        // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
-        ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset * asset) {
-            if (asset) {
-                // We have the asset!  Get the data and send it off.
-                ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
-                Byte* buffer = (Byte*)malloc ([assetRepresentation size]);
-                NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil];
-                NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
-                NSString* mimeType = [self getMimeTypeFromPath:[assetRepresentation filename]];
-                NSString* dataString = [NSString stringWithFormat:@"data:%@;base64,%@", mimeType, [data base64EncodedString]];
-                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:dataString];
-                [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
-            } else {
-                // We couldn't find the asset.  Send the appropriate error.
-                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
-                [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
-            }
-        };
-        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) {
-            // Retrieving the asset failed for some reason.  Send the appropriate error.
-            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]];
-            [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
-        };
+/* Read content of text file and return as an arraybuffer
+ * IN:
+ * NSArray* arguments
+ *	0 - NSString* fullPath
+ *	1 - NSString* start
+ *	2 - NSString* end
+ */
 
-        ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
-        [assetsLibrary assetForURL:[NSURL URLWithString:argPath] resultBlock:resultBlock failureBlock:failureBlock];
-        return;
-    } else {
-        NSString* mimeType = [self getMimeTypeFromPath:argPath];
-        if (!mimeType) {
-            // can't return as data URL if can't figure out the mimeType
-            errCode = ENCODING_ERR;
+- (void)readAsArrayBuffer:(CDVInvokedUrlCommand*)command
+{
+    NSString* path = [command argumentAtIndex:0];
+    NSInteger start = [[command argumentAtIndex:1] integerValue];
+    NSInteger end = [[command argumentAtIndex:2] integerValue];
+
+    [self readFileWithPath:path start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) {
+        CDVPluginResult* result = nil;
+        if (data != nil) {
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArrayBuffer:data];
         } else {
-            NSFileHandle* file = [NSFileHandle fileHandleForReadingAtPath:argPath];
-            if (start > 0) {
-                [file seekToFileOffset:start];
-            }
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
+        }
 
-            NSData* readData;
-            if (end < 0) {
-                readData = [file readDataToEndOfFile];
-            } else {
-                readData = [file readDataOfLength:(end - start)];
-            }
+        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+    }];
+}
 
-            [file closeFile];
-            if (readData) {
-                NSString* output = [NSString stringWithFormat:@"data:%@;base64,%@", mimeType, [readData base64EncodedString]];
-                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:output];
-            } else {
-                errCode = NOT_FOUND_ERR;
-            }
+- (void)readAsBinaryString:(CDVInvokedUrlCommand*)command
+{
+    NSString* path = [command argumentAtIndex:0];
+    NSInteger start = [[command argumentAtIndex:1] integerValue];
+    NSInteger end = [[command argumentAtIndex:2] integerValue];
+
+    [self readFileWithPath:path start:start end:end callback:^(NSData* data, NSString* mimeType, CDVFileError errorCode) {
+        CDVPluginResult* result = nil;
+        if (data != nil) {
+            NSString* payload = [[NSString alloc] initWithBytesNoCopy:(void*)[data bytes] length:[data length] encoding:NSASCIIStringEncoding freeWhenDone:NO];
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:payload];
+            result.associatedObject = data;
+        } else {
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:errorCode];
         }
-    }
-    if (!result) {
-        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsInt:errCode];
-    }
-    // NSLog(@"readAsDataURL return: %@", jsString);
-    [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+
+        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+    }];
 }
 
 /* helper function to get the mimeType from the file extension
@@ -1219,7 +1246,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
             mimeType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass(typeId, kUTTagClassMIMEType);
             if (!mimeType) {
                 // special case for m4a
-                if ([(__bridge NSString*) typeId rangeOfString:@"m4a-audio"].location != NSNotFound) {
+                if ([(__bridge NSString*)typeId rangeOfString : @"m4a-audio"].location != NSNotFound) {
                     mimeType = @"audio/mp4";
                 } else if ([[fullPath pathExtension] rangeOfString:@"wav"].location != NSNotFound) {
                     mimeType = @"audio/wav";
@@ -1343,7 +1370,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
     NSString* appFile = argPath; // [ self getFullPath: argPath];
 
     BOOL bExists = [fMgr fileExistsAtPath:appFile];
-    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(bExists ? 1:0)];
+    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(bExists ? 1 : 0)];
 
     [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
 }
@@ -1359,7 +1386,7 @@ NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
     BOOL bIsDir = NO;
     BOOL bExists = [fMgr fileExistsAtPath:appFile isDirectory:&bIsDir];
 
-    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:((bExists && bIsDir) ? 1:0)];
+    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:((bExists && bIsDir) ? 1 : 0)];
 
     [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
 }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
index f96bb7d..d82cdd3 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
@@ -48,10 +48,10 @@ extern NSString* const kOptionsKeyCookie;
 - (NSMutableDictionary*)createFileTransferError:(int)code AndSource:(NSString*)source AndTarget:(NSString*)target;
 
 - (NSMutableDictionary*)createFileTransferError:(int)code
-       AndSource                                   :(NSString*)source
-       AndTarget                                   :(NSString*)target
-   AndHttpStatus                               :(int)httpStatus
-         AndBody                                     :(NSString*)body;
+                                      AndSource:(NSString*)source
+                                      AndTarget:(NSString*)target
+                                  AndHttpStatus:(int)httpStatus
+                                        AndBody:(NSString*)body;
 @property (readonly) NSMutableDictionary* activeTransfers;
 @end
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
index 4ccdce6..5741aca 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
@@ -52,8 +52,8 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
 
     while (totalBytesWritten < bytesToWrite) {
         CFIndex result = CFWriteStreamWrite(stream,
-            bytes + totalBytesWritten,
-            bytesToWrite - totalBytesWritten);
+                bytes + totalBytesWritten,
+                bytesToWrite - totalBytesWritten);
         if (result < 0) {
             CFStreamError error = CFWriteStreamGetError(stream);
             NSLog(@"WriteStreamError domain: %ld error: %ld", error.domain, error.error);
@@ -190,7 +190,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
         [postBodyBeforeFile appendData:formBoundaryData];
         [postBodyBeforeFile appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]];
         [postBodyBeforeFile appendData:[val dataUsingEncoding:NSUTF8StringEncoding]];
-        [postBodyBeforeFile appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
+        [postBodyBeforeFile appendData:[@"\r\n" dataUsingEncoding : NSUTF8StringEncoding]];
     }
 
     [postBodyBeforeFile appendData:formBoundaryData];
@@ -213,22 +213,22 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
         [req setHTTPBodyStream:CFBridgingRelease(readStream)];
 
         [self.commandDelegate runInBackground:^{
-                if (CFWriteStreamOpen (writeStream)) {
-                    NSData* chunks[] = {postBodyBeforeFile, fileData, postBodyAfterFile};
-                    int numChunks = sizeof (chunks) / sizeof (chunks[0]);
-
-                    for (int i = 0; i < numChunks; ++i) {
-                        CFIndex result = WriteDataToStream (chunks[i], writeStream);
-                        if (result <= 0) {
-                            break;
-                        }
+            if (CFWriteStreamOpen(writeStream)) {
+                NSData* chunks[] = {postBodyBeforeFile, fileData, postBodyAfterFile};
+                int numChunks = sizeof(chunks) / sizeof(chunks[0]);
+
+                for (int i = 0; i < numChunks; ++i) {
+                    CFIndex result = WriteDataToStream(chunks[i], writeStream);
+                    if (result <= 0) {
+                        break;
                     }
-                } else {
-                    NSLog (@"FileTransfer: Failed to open writeStream");
                 }
-                CFWriteStreamClose (writeStream);
-                CFRelease (writeStream);
-            }];
+            } else {
+                NSLog(@"FileTransfer: Failed to open writeStream");
+            }
+            CFWriteStreamClose(writeStream);
+            CFRelease(writeStream);
+        }];
     } else {
         [postBodyBeforeFile appendData:fileData];
         [postBodyBeforeFile appendData:postBodyAfterFile];
@@ -265,11 +265,11 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     // return unsupported result for assets-library URLs
     if ([target hasPrefix:kCDVAssetsLibraryPrefix]) {
         // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
-        ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset * asset) {
+        ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
             if (asset) {
                 // We have the asset!  Get the data and send it off.
                 ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
-                Byte* buffer = (Byte*)malloc ([assetRepresentation size]);
+                Byte* buffer = (Byte*)malloc([assetRepresentation size]);
                 NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil];
                 NSData* fileData = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
                 [self uploadData:fileData command:command];
@@ -279,7 +279,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
                 [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
             }
         };
-        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) {
+        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
             // Retrieving the asset failed for some reason.  Send the appropriate error.
             CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]];
             [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
@@ -291,12 +291,18 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     } else {
         // Extract the path part out of a file: URL.
         NSString* filePath = [target hasPrefix:@"/"] ? [target copy] : [[NSURL URLWithString:target] path];
+        if (filePath == nil) {
+            // We couldn't find the asset.  Send the appropriate error.
+            CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
+            [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+            return;
+        }
 
         // Memory map the file so that it can be read efficiently even if it is large.
         NSData* fileData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&err];
 
         if (err != nil) {
-            NSLog (@"Error opening file %@: %@", target, err);
+            NSLog(@"Error opening file %@: %@", target, err);
         }
         [self uploadData:fileData command:command];
     }
@@ -352,6 +358,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     NSString* filePath = [command.arguments objectAtIndex:1];
     BOOL trustAllHosts = [[command.arguments objectAtIndex:2 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs
     NSString* objectId = [command.arguments objectAtIndex:3];
+    NSDictionary* headers = [command.arguments objectAtIndex:4 withDefault:nil];
 
     // return unsupported result for assets-library URLs
     if ([filePath hasPrefix:kCDVAssetsLibraryPrefix]) {
@@ -388,7 +395,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     }
 
     NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url];
-    [self applyRequestHeaders:nil toRequest:req];
+    [self applyRequestHeaders:headers toRequest:req];
 
     CDVFileTransferDelegate* delegate = [[CDVFileTransferDelegate alloc] init];
     delegate.command = self;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m b/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m
index 4d960cd..9eb9721 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVGlobalization.m
@@ -138,14 +138,14 @@
 
     // create the formatter using the user's current default locale and formats for dates and times
     CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        dateStyle,
-        timeStyle);
+            currentLocale,
+            dateStyle,
+            timeStyle);
     // if we have a valid date object then call the formatter
     if (date) {
         dateString = (__bridge_transfer NSString*)CFDateFormatterCreateStringWithDate(kCFAllocatorDefault,
-            formatter,
-            (__bridge CFDateRef)date);
+                formatter,
+                (__bridge CFDateRef)date);
     }
 
     // if the date was converted to a string successfully then return the result
@@ -227,18 +227,18 @@
 
     // get the user's default settings for date and time formats
     CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        dateStyle,
-        timeStyle);
+            currentLocale,
+            dateStyle,
+            timeStyle);
 
     // set the parsing to be more lenient
     CFDateFormatterSetProperty(formatter, kCFDateFormatterIsLenient, kCFBooleanTrue);
 
     // parse tha date and time string
     CFDateRef date = CFDateFormatterCreateDateFromString(kCFAllocatorDefault,
-        formatter,
-        (__bridge CFStringRef)dateString,
-        NULL);
+            formatter,
+            (__bridge CFStringRef)dateString,
+            NULL);
 
     // if we were able to parse the date then get the date and time components
     if (date != NULL) {
@@ -336,9 +336,9 @@
 
     // get the user's default settings for date and time formats
     CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        dateStyle,
-        timeStyle);
+            currentLocale,
+            dateStyle,
+            timeStyle);
 
     // get the date pattern to apply when formatting and parsing
     CFStringRef datePattern = CFDateFormatterGetFormat(formatter);
@@ -415,9 +415,9 @@
     }
 
     CFDateFormatterRef formatter = CFDateFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        kCFDateFormatterFullStyle,
-        kCFDateFormatterFullStyle);
+            currentLocale,
+            kCFDateFormatterFullStyle,
+            kCFDateFormatterFullStyle);
 
     if ((selector == CDV_SELECTOR_MONTHS) && (style == CDV_FORMAT_LONG)) {
         dataStyle = kCFDateFormatterMonthSymbols;
@@ -545,13 +545,13 @@
     }
 
     CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        style);
+            currentLocale,
+            style);
 
     // get the localized string based upon the locale and user preferences
     NSString* numberString = (__bridge_transfer NSString*)CFNumberFormatterCreateStringWithNumber(kCFAllocatorDefault,
-        formatter,
-        (__bridge CFNumberRef)number);
+            formatter,
+            (__bridge CFNumberRef)number);
 
     if (numberString) {
         NSDictionary* dictionary = [NSDictionary dictionaryWithObject:numberString forKey:@"value"];
@@ -612,8 +612,8 @@
     }
 
     CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        style);
+            currentLocale,
+            style);
 
     // we need to make this lenient so as to avoid problems with parsing currencies that have non-breaking space characters
     if (style == kCFNumberFormatterCurrencyStyle) {
@@ -622,10 +622,10 @@
 
     // parse againist the largest type to avoid data loss
     Boolean rc = CFNumberFormatterGetValueFromString(formatter,
-        (__bridge CFStringRef)numberString,
-        NULL,
-        kCFNumberDoubleType,
-        &doubleValue);
+            (__bridge CFStringRef)numberString,
+            NULL,
+            kCFNumberDoubleType,
+            &doubleValue);
 
     if (rc) {
         NSDictionary* dictionary = [NSDictionary dictionaryWithObject:[NSNumber numberWithDouble:doubleValue] forKey:@"value"];
@@ -681,8 +681,8 @@
     }
 
     CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
-        currentLocale,
-        style);
+            currentLocale,
+            style);
 
     NSString* numberPattern = (__bridge NSString*)CFNumberFormatterGetFormat(formatter);
 
@@ -749,8 +749,8 @@
     // now set the currency code in the formatter
     if (rc) {
         CFNumberFormatterRef formatter = CFNumberFormatterCreate(kCFAllocatorDefault,
-            currentLocale,
-            kCFNumberFormatterCurrencyStyle);
+                currentLocale,
+                kCFNumberFormatterCurrencyStyle);
 
         CFNumberFormatterSetProperty(formatter, kCFNumberFormatterCurrencyCode, (__bridge CFStringRef)currencyCode);
         CFNumberFormatterSetProperty(formatter, kCFNumberFormatterInternationalCurrencySymbol, (__bridge CFStringRef)currencyCode);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
index 9ff460a..f63250a 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
@@ -20,6 +20,7 @@
 #import "CDVPlugin.h"
 #import "CDVInvokedUrlCommand.h"
 #import "CDVScreenOrientationDelegate.h"
+#import "CDVWebViewDelegate.h"
 
 @class CDVInAppBrowserViewController;
 
@@ -27,6 +28,7 @@
 
 - (void)browserLoadStart:(NSURL*)url;
 - (void)browserLoadStop:(NSURL*)url;
+- (void)browserLoadError:(NSError*)error forUrl:(NSURL*)url;
 - (void)browserExit;
 
 @end
@@ -47,6 +49,7 @@
     NSString* _userAgent;
     NSString* _prevUserAgent;
     NSInteger _userAgentLockToken;
+    CDVWebViewDelegate* _webViewDelegate;
 }
 
 @property (nonatomic, strong) IBOutlet UIWebView* webView;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
index 14671a5..d001dfd 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
@@ -165,7 +165,7 @@
 {
     if (self.callbackId != nil) {
         CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
-                                                      messageAsDictionary:@ {@"type":@"loadstart", @"url":[url absoluteString]}];
+                                                      messageAsDictionary:@{@"type":@"loadstart", @"url":[url absoluteString]}];
         [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
 
         [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
@@ -176,7 +176,18 @@
 {
     if (self.callbackId != nil) {
         CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
-                                                      messageAsDictionary:@ {@"type":@"loadstop", @"url":[url absoluteString]}];
+                                                      messageAsDictionary:@{@"type":@"loadstop", @"url":[url absoluteString]}];
+        [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
+
+        [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
+    }
+}
+
+- (void)browserLoadError:(NSError*)error forUrl:(NSURL*)url
+{
+    if (self.callbackId != nil) {
+        CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR
+                                                      messageAsDictionary:@{@"type":@"loaderror", @"url":[url absoluteString], @"code": [NSNumber numberWithInt:error.code], @"message": error.localizedDescription}];
         [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
 
         [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
@@ -187,7 +198,7 @@
 {
     if (self.callbackId != nil) {
         CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
-                                                      messageAsDictionary:@ {@"type":@"exit"}];
+                                                      messageAsDictionary:@{@"type":@"exit"}];
         [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
 
         [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
@@ -209,6 +220,7 @@
     if (self != nil) {
         _userAgent = userAgent;
         _prevUserAgent = prevUserAgent;
+        _webViewDelegate = [[CDVWebViewDelegate alloc] initWithDelegate:self];
         [self createViews];
     }
 
@@ -229,7 +241,7 @@
     [self.view addSubview:self.webView];
     [self.view sendSubviewToBack:self.webView];
 
-    self.webView.delegate = self;
+    self.webView.delegate = _webViewDelegate;
     self.webView.backgroundColor = [UIColor whiteColor];
 
     self.webView.clearsContextBeforeDrawing = YES;
@@ -391,10 +403,10 @@
         [self.webView loadRequest:request];
     } else {
         [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) {
-                _userAgentLockToken = lockToken;
-                [CDVUserAgentUtil setUserAgent:_userAgent lockToken:lockToken];
-                [self.webView loadRequest:request];
-            }];
+            _userAgentLockToken = lockToken;
+            [CDVUserAgentUtil setUserAgent:_userAgent lockToken:lockToken];
+            [self.webView loadRequest:request];
+        }];
     }
 }
 
@@ -419,14 +431,18 @@
     self.forwardButton.enabled = theWebView.canGoForward;
 
     [self.spinner startAnimating];
+}
 
+- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
+{
     if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadStart:)]) {
-        NSURL* url = theWebView.request.URL;
+        NSURL* url = request.URL;
         if (url == nil) {
             url = _requestedURL;
         }
         [self.navigationDelegate browserLoadStart:url];
     }
+    return YES;
 }
 
 - (void)webViewDidFinishLoad:(UIWebView*)theWebView
@@ -450,7 +466,7 @@
     //    from it must pass through its white-list. This *does* break PDFs that
     //    contain links to other remote PDF/websites.
     // More info at https://issues.apache.org/jira/browse/CB-2225
-    BOOL isPDF = [@"true" isEqualToString:[theWebView stringByEvaluatingJavaScriptFromString:@"document.body==null"]];
+    BOOL isPDF = [@"true" isEqualToString :[theWebView stringByEvaluatingJavaScriptFromString:@"document.body==null"]];
     if (isPDF) {
         [CDVUserAgentUtil setUserAgent:_prevUserAgent lockToken:_userAgentLockToken];
     }
@@ -471,6 +487,11 @@
     [self.spinner stopAnimating];
 
     self.addressLabel.text = @"Load Error";
+
+    if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserLoadError:forUrl:)]) {
+        NSURL* url = theWebView.request.URL;
+        [self.navigationDelegate browserLoadError:error forUrl:url];
+    }
 }
 
 #pragma mark CDVScreenOrientationDelegate

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h b/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h
index 6eb0099..7be8884 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInvokedUrlCommand.h
@@ -34,9 +34,9 @@
 + (CDVInvokedUrlCommand*)commandFromJson:(NSArray*)jsonEntry;
 
 - (id)initWithArguments:(NSArray*)arguments
-   callbackId          :(NSString*)callbackId
-    className           :(NSString*)className
-   methodName          :(NSString*)methodName;
+             callbackId:(NSString*)callbackId
+              className:(NSString*)className
+             methodName:(NSString*)methodName;
 
 - (id)initFromJson:(NSArray*)jsonEntry;
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.h b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.h
new file mode 100644
index 0000000..02fe91f
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.h
@@ -0,0 +1,60 @@
+/*
+ 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+@interface CDVJpegHeaderWriter : NSObject {
+    NSDictionary * SubIFDTagFormatDict;
+    NSDictionary * IFD0TagFormatDict;
+}
+
+- (NSString*) createExifAPP1 : (NSDictionary*) datadict;
+- (NSString*) formattedHexStringFromDecimalNumber: (NSNumber*) numb 
+                                       withPlaces: (NSNumber*) width;
+- (NSString*) formatNumberWithLeadingZeroes: (NSNumber*) numb 
+                                 withPlaces: (NSNumber*) places;
+- (NSString*) decimalToUnsignedRational: (NSNumber*) numb
+                    withResultNumerator: (NSNumber**) numerator
+                  withResultDenominator: (NSNumber**) denominator;
+- (void) continuedFraction: (double) val
+          withFractionList: (NSMutableArray*) fractionlist 
+               withHorizon: (int) horizon;
+//- (void) expandContinuedFraction: (NSArray*) fractionlist;
+- (void) splitDouble: (double) val 
+         withIntComponent: (int*) rightside 
+         withFloatRemainder: (double*) leftside;
+- (NSString*) formatRationalWithNumerator: (NSNumber*) numerator
+                          withDenominator: (NSNumber*) denominator
+                               asSigned: (Boolean) signedFlag;
+- (NSString*) hexStringFromData : (NSData*) data;
+- (NSNumber*) numericFromHexString : (NSString *) hexstring;
+
+/*
+- (void) readExifMetaData : (NSData*) imgdata;
+- (void) spliceImageData : (NSData*) imgdata withExifData: (NSDictionary*) exifdata;
+- (void) locateExifMetaData : (NSData*) imgdata;
+- (NSString*) createExifAPP1 : (NSDictionary*) datadict;
+- (void) createExifDataString : (NSDictionary*) datadict;
+- (NSString*) createDataElement : (NSString*) element
+              withElementData: (NSString*) data
+              withExternalDataBlock: (NSDictionary*) memblock;
+- (NSString*) hexStringFromData : (NSData*) data;
+- (NSNumber*) numericFromHexString : (NSString *) hexstring;
+*/
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m
new file mode 100644
index 0000000..7b59d11
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVJpegHeaderWriter.m
@@ -0,0 +1,472 @@
+/*
+ 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.
+ */
+
+#import "CDVJpegHeaderWriter.h"
+#include "CDVExif.h"
+
+// tag info shorthand, tagno: tag number, typecode: data type:, components: number of components
+#define TAGINF(tagno, typecode, components) [NSArray arrayWithObjects: tagno, typecode, components, nil]
+
+const uint mJpegId = 0xffd8; // JPEG format marker
+const uint mExifMarker = 0xffe1; // APP1 jpeg header marker
+const uint mExif = 0x45786966; // ASCII 'Exif', first characters of valid exif header after size
+const uint mMotorallaByteAlign = 0x4d4d; // 'MM', motorola byte align, msb first or 'sane'
+const uint mIntelByteAlgin = 0x4949; // 'II', Intel byte align, lsb first or 'batshit crazy reverso world'
+const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a(MM) or 0x2a00(II), tiff version number
+
+
+@implementation CDVJpegHeaderWriter
+
+- (id) init {    
+    self = [super init];
+    // supported tags for exif IFD
+    IFD0TagFormatDict = [[NSDictionary alloc] initWithObjectsAndKeys:
+                  //      TAGINF(@"010e", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"ImageDescription",
+                        TAGINF(@"0132", [NSNumber numberWithInt:EDT_ASCII_STRING], @20), @"DateTime",
+                        TAGINF(@"010f", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Make",
+                        TAGINF(@"0110", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Model",
+                        TAGINF(@"0131", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Software",
+                        TAGINF(@"011a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"XResolution",
+                        TAGINF(@"011b", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"YResolution",
+                        // currently supplied outside of Exif data block by UIImagePickerControllerMediaMetadata, this is set manually in CDVCamera.m
+                        TAGINF(@"0112", [NSNumber numberWithInt:EDT_USHORT], @1), @"Orientation",
+                       
+                        // rest of the tags are supported by exif spec, but are not specified by UIImagePickerControllerMediaMedadata
+                        // should camera hardware supply these values in future versions, or if they can be derived, ImageHeaderWriter will include them gracefully
+                        TAGINF(@"0128", [NSNumber numberWithInt:EDT_USHORT], @1), @"ResolutionUnit",
+                        TAGINF(@"013e", [NSNumber numberWithInt:EDT_URATIONAL], @2), @"WhitePoint",
+                        TAGINF(@"013f", [NSNumber numberWithInt:EDT_URATIONAL], @6), @"PrimaryChromaticities",
+                        TAGINF(@"0211", [NSNumber numberWithInt:EDT_URATIONAL], @3), @"YCbCrCoefficients",
+                        TAGINF(@"0213", [NSNumber numberWithInt:EDT_USHORT], @1), @"YCbCrPositioning",
+                        TAGINF(@"0214", [NSNumber numberWithInt:EDT_URATIONAL], @6), @"ReferenceBlackWhite",
+                        TAGINF(@"8298", [NSNumber numberWithInt:EDT_URATIONAL], @0), @"Copyright",
+                         
+                        // offset to exif subifd, we determine this dynamically based on the size of the main exif IFD
+                        TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1), @"ExifOffset",
+                        nil];
+
+    // supported tages for exif subIFD
+    SubIFDTagFormatDict = [[NSDictionary alloc] initWithObjectsAndKeys:
+                          // TAGINF(@"9000", [NSNumber numberWithInt:], @), @"ExifVersion",
+                           // TAGINF(@"9202",[NSNumber numberWithInt:EDT_URATIONAL],@1), @"ApertureValue",
+                           // TAGINF(@"9203",[NSNumber numberWithInt:EDT_SRATIONAL],@1), @"BrightnessValue",
+                           TAGINF(@"a001",[NSNumber numberWithInt:EDT_USHORT],@1), @"ColorSpace",
+                           TAGINF(@"9004",[NSNumber numberWithInt:EDT_ASCII_STRING],@20), @"DateTimeDigitized",
+                           TAGINF(@"9003",[NSNumber numberWithInt:EDT_ASCII_STRING],@20), @"DateTimeOriginal",
+                           TAGINF(@"a402", [NSNumber numberWithInt:EDT_USHORT], @1), @"ExposureMode",
+                           TAGINF(@"8822", [NSNumber numberWithInt:EDT_USHORT], @1), @"ExposureProgram",
+                           TAGINF(@"829a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"ExposureTime",
+                           TAGINF(@"829d", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"FNumber",
+                           TAGINF(@"9209", [NSNumber numberWithInt:EDT_USHORT], @1), @"Flash",
+                           // FocalLengthIn35mmFilm
+                           TAGINF(@"a405", [NSNumber numberWithInt:EDT_USHORT], @1), @"FocalLenIn35mmFilm",
+                           TAGINF(@"920a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"FocalLength",
+
+                           //TAGINF(@"8827", [NSNumber numberWithInt:EDT_USHORT], @2), @"ISOSpeedRatings",
+
+                           TAGINF(@"9207",[NSNumber numberWithInt:EDT_USHORT],@1), @"MeteringMode",
+                           // specific to compressed data
+                           TAGINF(@"a002", [NSNumber numberWithInt:EDT_ULONG],@1), @"PixelXDimension",
+                           TAGINF(@"a003", [NSNumber numberWithInt:EDT_ULONG],@1), @"PixelYDimension",
+                           // data type undefined, but this is a DSC camera, so value is always 1, treat as ushort
+                           TAGINF(@"a301", [NSNumber numberWithInt:EDT_USHORT],@1), @"SceneType",
+                           TAGINF(@"a217",[NSNumber numberWithInt:EDT_USHORT],@1), @"SensingMethod",
+                    // TAGINF(@"9201", [NSNumber numberWithInt:EDT_SRATIONAL], @1), @"ShutterSpeedValue",
+                           // specifies location of main subject in scene (x,y,wdith,height) expressed before rotation processing
+                           // TAGINF(@"9214", [NSNumber numberWithInt:EDT_USHORT], @4), @"SubjectArea",
+                           TAGINF(@"a403", [NSNumber numberWithInt:EDT_USHORT], @1), @"WhiteBalance",
+                      nil];
+    return self;
+}
+
+/**
+ * Create the Exif data block as a hex string
+ *   jpeg uses Application Markers (APP's) as markers for application data
+ *   APP1 is the application marker reserved for exif data
+ *
+ *   (NSDictionary*) datadict - with subdictionaries marked '{TIFF}' and '{EXIF}' as returned by imagePickerController with a valid
+ *                              didFinishPickingMediaWithInfo data dict, under key @"UIImagePickerControllerMediaMetadata"
+ *
+ *   the following constructs a hex string to Exif specifications, and is therefore brittle
+ *   altering the order of arguments to the string constructors, modifying field sizes or formats,
+ *   and any other minor change will likely prevent the exif data from being read
+ */
+- (NSString*) createExifAPP1 : (NSDictionary*) datadict {
+    NSMutableString * app1; // holds finalized product
+    NSString * exifIFD; // exif information file directory
+    NSString * subExifIFD; // subexif information file directory
+    
+    // FFE1 is the hex APP1 marker code, and will allow client apps to read the data
+    NSString * app1marker = @"ffe1";
+    // SSSS size, to be determined
+    // EXIF ascii characters followed by 2bytes of zeros
+    NSString * exifmarker = @"457869660000";
+    // Tiff header: 4d4d is motorolla byte align (big endian), 002a is hex for 42
+    NSString * tiffheader = @"4d4d002a";
+    //first IFD offset from the Tiff header to IFD0. Since we are writing it, we know it's address 0x08
+    NSString * ifd0offset = @"00000008";
+    
+    //data labeled as TIFF in UIImagePickerControllerMediaMetaData is part of the EXIF IFD0 portion of APP1
+    exifIFD = [self createExifIFDFromDict: [datadict objectForKey:@"{TIFF}"] withFormatDict: IFD0TagFormatDict isIFD0:YES];
+
+    //data labeled as EXIF in UIImagePickerControllerMediaMetaData is part of the EXIF Sub IFD portion of APP1
+    subExifIFD = [self createExifIFDFromDict: [datadict objectForKey:@"{Exif}"] withFormatDict: SubIFDTagFormatDict isIFD0:NO];
+
+    // construct the complete app1 data block
+    app1 = [[NSMutableString alloc] initWithFormat: @"%@%04x%@%@%@%@%@",
+            app1marker,
+            16+[exifIFD length]/2+[subExifIFD length]/2/*16+[exifIFD length]/2*/,
+            exifmarker,
+            tiffheader,
+            ifd0offset,
+            exifIFD,
+            subExifIFD];
+     
+    return app1;
+}
+
+// returns hex string representing a valid exif information file directory constructed from the datadict and formatdict
+- (NSString*) createExifIFDFromDict : (NSDictionary*) datadict withFormatDict : (NSDictionary*) formatdict isIFD0 : (BOOL) ifd0flag {
+    NSArray * datakeys = [datadict allKeys]; // all known data keys 
+    NSArray * knownkeys = [formatdict  allKeys]; // only keys in knowkeys are considered for entry in this IFD
+    NSMutableArray * ifdblock = [[NSMutableArray alloc] initWithCapacity: [datadict count]]; // all ifd entries
+    NSMutableArray * ifddatablock = [[NSMutableArray alloc] initWithCapacity: [datadict count]]; // data block entries
+    ifd0flag = NO; // ifd0 requires a special flag and has offset to next ifd appended to end
+    
+    // iterate through known provided data keys
+    for (int i = 0; i < [datakeys count]; i++) {
+        NSString * key = [datakeys objectAtIndex:i];
+        // don't muck about with unknown keys
+        if ([knownkeys indexOfObject: key] != NSNotFound) {
+            // create new IFD entry
+            NSString * entry = [self  createIFDElement: key
+                                      withFormatDict: formatdict
+                                      withElementData: [datadict objectForKey:key]];
+            // create the IFD entry's data block
+            NSString * data = [self createIFDElementDataWithFormat: [formatdict objectForKey:key]
+                                                   withData: [datadict objectForKey:key]];
+            if (entry) {
+                [ifdblock addObject:entry];
+                if(!data) {
+                    [ifdblock addObject:@""];
+                } else {
+                    [ifddatablock addObject:data];
+                }
+            }
+        }
+    }
+    
+    NSMutableString * exifstr = [[NSMutableString alloc] initWithCapacity: [ifdblock count] * 24];
+    NSMutableString * dbstr = [[NSMutableString alloc] initWithCapacity: 100];
+    
+    int addr=0; // current offset/address in datablock
+    if (ifd0flag) {
+        // calculate offset to datablock based on ifd file entry count
+        addr = 14+(12*([ifddatablock count]+1)); // +1 for tag 0x8769, exifsubifd offset
+    } else {
+        // same calculation as above, but no exifsubifd offset
+        addr = 14+12*[ifddatablock count];
+    }
+    
+    for (int i = 0; i < [ifdblock count]; i++) {
+        NSString * entry = [ifdblock objectAtIndex:i];
+        NSString * data = [ifddatablock objectAtIndex:i];
+        
+        // check if the data fits into 4 bytes
+        if( [data length] <= 8) {
+            // concatenate the entry and the (4byte) data entry into the final IFD entry and append to exif ifd string
+            [exifstr appendFormat : @"%@%@", entry, data];
+        } else {
+            [exifstr appendFormat : @"%@%08x", entry, addr];
+            [dbstr appendFormat: @"%@", data]; 
+            addr+= [data length] / 2;
+        }
+    }
+    
+    // calculate IFD0 terminal offset tags, currently ExifSubIFD
+    int entrycount = [ifdblock count];
+    if (ifd0flag) {
+        NSNumber * offset = [NSNumber numberWithInt:[exifstr length] / 2 + [dbstr length] / 2 ];
+        
+        [self appendExifOffsetTagTo: exifstr
+                        withOffset : offset];
+        entrycount++;
+    } 
+    return [[NSString alloc] initWithFormat: @"%04x%@%@%@",
+            entrycount,
+            exifstr,
+            @"00000000", // offset to next IFD, 0 since there is none
+            dbstr]; // lastly, the datablock
+}
+
+// Creates an exif formatted exif information file directory entry
+- (NSString*) createIFDElement: (NSString*) elementName withFormatDict : (NSDictionary*) formatdict withElementData : (NSString*) data  {
+    NSArray * fielddata = [formatdict objectForKey: elementName];// format data of desired field
+    if (fielddata) {
+        // format string @"%@%@%@%@", tag number, data format, components, value
+        NSNumber * dataformat = [fielddata objectAtIndex:1];
+        NSNumber * components = [fielddata objectAtIndex:2];
+        if([components intValue] == 0) {
+            components = [NSNumber numberWithInt: [data length] * DataTypeToWidth[[dataformat intValue]-1]];            
+        }
+
+        return [[NSString alloc] initWithFormat: @"%@%@%08x",
+                                                [fielddata objectAtIndex:0], // the field code
+                                                [self formatNumberWithLeadingZeroes: dataformat withPlaces: @4], // the data type code
+                                                [components intValue]]; // number of components
+    }
+    return NULL;
+}
+
+/**
+ * appends exif IFD0 tag 8769 "ExifOffset" to the string provided
+ * (NSMutableString*) str - string you wish to append the 8769 tag to: APP1 or IFD0 hex data string 
+ *  //  TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1), @"ExifOffset",
+ */
+- (void) appendExifOffsetTagTo: (NSMutableString*) str withOffset : (NSNumber*) offset {
+    NSArray * format = TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1);
+    
+    NSString * entry = [self  createIFDElement: @"ExifOffset"
+                                withFormatDict: IFD0TagFormatDict
+                               withElementData: [offset stringValue]];
+    
+    NSString * data = [self createIFDElementDataWithFormat: format
+                                                  withData: [offset stringValue]];
+    [str appendFormat:@"%@%@", entry, data];
+}
+
+// formats the Information File Directory Data to exif format
+- (NSString*) createIFDElementDataWithFormat: (NSArray*) dataformat withData: (NSString*) data {
+    NSMutableString * datastr = nil;
+    NSNumber * tmp = nil;
+    NSNumber * formatcode = [dataformat objectAtIndex:1];
+    NSNumber * num = @0;
+    NSNumber * denom = @0;
+    
+    switch ([formatcode intValue]) {
+        case EDT_UBYTE:
+            break;
+        case EDT_ASCII_STRING:
+            datastr = [[NSMutableString alloc] init];
+            for (int i = 0; i < [data length]; i++) {
+                [datastr appendFormat:@"%02x",[data characterAtIndex:i]];
+            }
+            if ([datastr length] < 8) {
+                NSString * format = [NSString stringWithFormat:@"%%0%dd", 8 - [datastr length]];
+                [datastr appendFormat:format,0];
+            }
+            return datastr;
+        case EDT_USHORT:
+            return [[NSString alloc] initWithFormat : @"%@%@",
+                    [self formattedHexStringFromDecimalNumber: [NSNumber numberWithInt: [data intValue]] withPlaces: @4],
+                    @"00000000"];
+        case EDT_ULONG:
+            tmp = [NSNumber numberWithUnsignedLong:[data intValue]];
+            return [NSString stringWithFormat : @"%@",
+                    [self formattedHexStringFromDecimalNumber: tmp withPlaces: @8]];
+        case EDT_URATIONAL:
+            return [self decimalToUnsignedRational: [NSNumber numberWithDouble:[data doubleValue]]
+                               withResultNumerator: &num
+                             withResultDenominator: &denom];
+        case EDT_SBYTE:
+            
+            break;
+        case EDT_UNDEFINED:
+            break;     // 8 bits
+        case EDT_SSHORT:
+            
+            break;
+        case EDT_SLONG:
+            break;          // 32bit signed integer (2's complement)
+        case EDT_SRATIONAL:
+            break;     // 2 SLONGS, first long is numerator, second is denominator
+        case EDT_SINGLEFLOAT:
+            break;
+        case EDT_DOUBLEFLOAT:
+            break;
+    }
+    return datastr;
+}
+
+//======================================================================================================================
+// Utility Methods
+//======================================================================================================================
+
+// creates a formatted little endian hex string from a number and width specifier
+- (NSString*) formattedHexStringFromDecimalNumber: (NSNumber*) numb withPlaces: (NSNumber*) width {
+    NSMutableString * str = [[NSMutableString alloc] initWithCapacity:[width intValue]];
+    NSString * formatstr = [[NSString alloc] initWithFormat: @"%%%@%dx", @"0", [width intValue]];
+    [str appendFormat:formatstr, [numb intValue]];
+    return str;
+}
+
+// format number as string with leading 0's
+- (NSString*) formatNumberWithLeadingZeroes: (NSNumber *) numb withPlaces: (NSNumber *) places { 
+    NSNumberFormatter * formatter = [[NSNumberFormatter alloc] init];
+    NSString *formatstr = [@"" stringByPaddingToLength:[places unsignedIntegerValue] withString:@"0" startingAtIndex:0];
+    [formatter setPositiveFormat:formatstr];
+    return [formatter stringFromNumber:numb];
+}
+
+// approximate a decimal with a rational by method of continued fraction
+// can be collasped into decimalToUnsignedRational after testing
+- (void) decimalToRational: (NSNumber *) numb
+       withResultNumerator: (NSNumber**) numerator
+     withResultDenominator: (NSNumber**) denominator {
+    NSMutableArray * fractionlist = [[NSMutableArray alloc] initWithCapacity:8];
+    
+    [self continuedFraction: [numb doubleValue]
+           withFractionList: fractionlist
+                withHorizon: 8];
+    
+    // simplify complex fraction represented by partial fraction list
+    [self expandContinuedFraction: fractionlist
+              withResultNumerator: numerator
+            withResultDenominator: denominator];
+
+}
+
+// approximate a decimal with an unsigned rational by method of continued fraction
+- (NSString*) decimalToUnsignedRational: (NSNumber *) numb
+                          withResultNumerator: (NSNumber**) numerator
+                        withResultDenominator: (NSNumber**) denominator {
+    NSMutableArray * fractionlist = [[NSMutableArray alloc] initWithCapacity:8];
+    
+    // generate partial fraction list
+    [self continuedFraction: [numb doubleValue]
+           withFractionList: fractionlist
+                withHorizon: 8];
+    
+    // simplify complex fraction represented by partial fraction list
+    [self expandContinuedFraction: fractionlist
+              withResultNumerator: numerator
+            withResultDenominator: denominator];
+    
+    return [self formatFractionList: fractionlist];
+}
+
+// recursive implementation of decimal approximation by continued fraction
+- (void) continuedFraction: (double) val
+          withFractionList: (NSMutableArray*) fractionlist
+               withHorizon: (int) horizon {
+    int whole;
+    double remainder;
+    // 1. split term
+    [self splitDouble: val withIntComponent: &whole withFloatRemainder: &remainder];
+    [fractionlist addObject: [NSNumber numberWithInt:whole]];
+    
+    // 2. calculate reciprocal of remainder
+    if (!remainder) return; // early exit, exact fraction found, avoids recip/0
+    double recip = 1 / remainder;
+
+    // 3. exit condition
+    if ([fractionlist count] > horizon) {
+        return;
+    }
+    
+    // 4. recurse
+    [self continuedFraction:recip withFractionList: fractionlist withHorizon: horizon];
+    
+}
+
+// expand continued fraction list, creating a single level rational approximation
+-(void) expandContinuedFraction: (NSArray*) fractionlist
+                  withResultNumerator: (NSNumber**) numerator
+                withResultDenominator: (NSNumber**) denominator {
+    int i = 0;
+    int den = 0;
+    int num = 0;
+    if ([fractionlist count] == 1) {
+        *numerator = [NSNumber numberWithInt:[[fractionlist objectAtIndex:0] intValue]];
+        *denominator = @1;
+        return;
+    }
+    
+    //begin at the end of the list
+    i = [fractionlist count] - 1;
+    num = 1;
+    den = [[fractionlist objectAtIndex:i] intValue];
+    
+    while (i > 0) {
+        int t = [[fractionlist objectAtIndex: i-1] intValue];
+        num = t * den + num;
+        if (i==1) {
+            break;
+        } else {
+            t = num;
+            num = den;
+            den = t;
+        }
+        i--;
+    }
+    // set result parameters values
+    *numerator = [NSNumber numberWithInt: num];
+    *denominator = [NSNumber numberWithInt: den];
+}
+
+// formats expanded fraction list to string matching exif specification
+- (NSString*) formatFractionList: (NSArray *) fractionlist {
+    NSMutableString * str = [[NSMutableString alloc] initWithCapacity:16];
+    
+    if ([fractionlist count] == 1){
+        [str appendFormat: @"%08x00000001", [[fractionlist objectAtIndex:0] intValue]];
+    }
+    return str;
+}
+
+// format rational as
+- (NSString*) formatRationalWithNumerator: (NSNumber*) numerator withDenominator: (NSNumber*) denominator asSigned: (Boolean) signedFlag {
+    NSMutableString * str = [[NSMutableString alloc] initWithCapacity:16];
+    if (signedFlag) {
+        long num = [numerator longValue];
+        long den = [denominator longValue];
+        [str appendFormat: @"%08lx%08lx", num >= 0 ? num : ~ABS(num) + 1, num >= 0 ? den : ~ABS(den) + 1];
+    } else {
+        [str appendFormat: @"%08lx%08lx", [numerator unsignedLongValue], [denominator unsignedLongValue]];
+    }
+    return str;
+}
+
+// split a floating point number into two integer values representing the left and right side of the decimal
+- (void) splitDouble: (double) val withIntComponent: (int*) rightside withFloatRemainder: (double*) leftside {
+    *rightside = val; // convert numb to int representation, which truncates the decimal portion
+    *leftside = val - *rightside;
+}
+
+
+//
+- (NSString*) hexStringFromData : (NSData*) data {
+    //overflow detection
+    const unsigned char *dataBuffer = [data bytes];
+    return [[NSString alloc] initWithFormat: @"%02x%02x",
+            (unsigned char)dataBuffer[0],
+            (unsigned char)dataBuffer[1]];
+}
+
+// convert a hex string to a number
+- (NSNumber*) numericFromHexString : (NSString *) hexstring {
+    NSScanner * scan = NULL;
+    unsigned int numbuf= 0;
+    
+    scan = [NSScanner scannerWithString:hexstring];
+    [scan scanHexInt:&numbuf];
+    return [NSNumber numberWithInt:numbuf];
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
index cc6613f..dec6ab3 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
@@ -34,8 +34,8 @@
 + (void)__fixupDatabaseLocationsWithBackupType:(NSString*)backupType;
 // Visible for testing.
 + (BOOL)__verifyAndFixDatabaseLocationsWithAppPlistDict:(NSMutableDictionary*)appPlistDict
-    bundlePath                                          :(NSString*)bundlePath
-   fileManager                                         :(NSFileManager*)fileManager;
+                                             bundlePath:(NSString*)bundlePath
+                                            fileManager:(NSFileManager*)fileManager;
 @end
 
 @interface CDVBackupInfo : NSObject

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m
index 68175f1..238d680 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m
@@ -35,7 +35,7 @@
 {
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResignActive)
                                                  name:UIApplicationWillResignActiveNotification object:nil];
-    BOOL cloudBackup = [@"cloud" isEqualToString:self.commandDelegate.settings[@"BackupWebStorage"]];
+    BOOL cloudBackup = [@"cloud" isEqualToString : self.commandDelegate.settings[@"BackupWebStorage"]];
 
     self.backupInfo = [[self class] createBackupInfoWithCloudBackup:cloudBackup];
 }
@@ -64,8 +64,8 @@
     // ////////// LOCALSTORAGE
 
     original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/file__0.localstorage":@"file__0.localstorage"];
-    backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage":@"")];
-    backup = [backup stringByAppendingPathComponent:(rename ? @"localstorage.appdata.db":@"file__0.localstorage")];
+    backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")];
+    backup = [backup stringByAppendingPathComponent:(rename ? @"localstorage.appdata.db" : @"file__0.localstorage")];
 
     backupItem = [[CDVBackupInfo alloc] init];
     backupItem.backup = backup;
@@ -77,8 +77,8 @@
     // ////////// WEBSQL MAIN DB
 
     original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/Databases.db":@"Databases.db"];
-    backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage":@"")];
-    backup = [backup stringByAppendingPathComponent:(rename ? @"websqlmain.appdata.db":@"Databases.db")];
+    backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")];
+    backup = [backup stringByAppendingPathComponent:(rename ? @"websqlmain.appdata.db" : @"Databases.db")];
 
     backupItem = [[CDVBackupInfo alloc] init];
     backupItem.backup = backup;
@@ -90,8 +90,8 @@
     // ////////// WEBSQL DATABASES
 
     original = [targetDir stringByAppendingPathComponent:targetDirNests ? @"WebKit/LocalStorage/file__0":@"file__0"];
-    backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage":@"")];
-    backup = [backup stringByAppendingPathComponent:(rename ? @"websqldbs.appdata.db":@"file__0")];
+    backup = [backupDir stringByAppendingPathComponent:(backupDirNests ? @"WebKit/LocalStorage" : @"")];
+    backup = [backup stringByAppendingPathComponent:(rename ? @"websqldbs.appdata.db" : @"file__0")];
 
     backupItem = [[CDVBackupInfo alloc] init];
     backupItem.backup = backup;
@@ -106,8 +106,8 @@
 + (NSMutableArray*)createBackupInfoWithCloudBackup:(BOOL)cloudBackup
 {
     // create backup info from backup folder to caches folder
-    NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains (NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
-    NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
+    NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
+    NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
     NSString* cacheFolder = [appLibraryFolder stringByAppendingPathComponent:@"Caches"];
     NSString* backupsFolder = [appDocumentsFolder stringByAppendingPathComponent:@"Backups"];
 
@@ -131,7 +131,7 @@
     return success;
 }
 
-+ (BOOL)copyFrom:(NSString*)src to:(NSString*)dest error:(NSError * __autoreleasing*)error
++ (BOOL)copyFrom:(NSString*)src to:(NSString*)dest error:(NSError* __autoreleasing*)error
 {
     NSFileManager* fileManager = [NSFileManager defaultManager];
 
@@ -149,7 +149,7 @@
     // generate unique filepath in temp directory
     CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault);
     CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuidRef);
-    NSString* tempBackup = [[NSTemporaryDirectory () stringByAppendingPathComponent:(__bridge NSString*)uuidString] stringByAppendingPathExtension:@"bak"];
+    NSString* tempBackup = [[NSTemporaryDirectory() stringByAppendingPathComponent:(__bridge NSString*)uuidString] stringByAppendingPathExtension:@"bak"];
     CFRelease(uuidString);
     CFRelease(uuidRef);
 
@@ -334,8 +334,8 @@
         return;
     }
 
-    NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains (NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
-    NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains (NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
+    NSString* appLibraryFolder = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
+    NSString* appDocumentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
 
     NSMutableArray* backupInfo = [NSMutableArray arrayWithCapacity:0];
 
@@ -386,15 +386,15 @@
         backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
                 [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID];
                 backgroundTaskID = UIBackgroundTaskInvalid;
-                NSLog (@"Background task to backup WebSQL/LocalStorage expired.");
+                NSLog(@"Background task to backup WebSQL/LocalStorage expired.");
             }];
         CDVLocalStorage __weak* weakSelf = self;
         [self.commandDelegate runInBackground:^{
-                [weakSelf backup:nil];
+            [weakSelf backup:nil];
 
-                [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID];
-                backgroundTaskID = UIBackgroundTaskInvalid;
-            }];
+            [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskID];
+            backgroundTaskID = UIBackgroundTaskInvalid;
+        }];
     }
 }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVLocation.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVLocation.h b/lib/cordova-ios/CordovaLib/Classes/CDVLocation.h
index 7087d43..caf0798 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVLocation.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVLocation.h
@@ -83,11 +83,11 @@ typedef NSUInteger CDVLocationStatus;
 - (void)startLocation:(BOOL)enableHighAccuracy;
 
 - (void)locationManager:(CLLocationManager*)manager
-   didUpdateToLocation :(CLLocation*)newLocation
-          fromLocation        :(CLLocation*)oldLocation;
+    didUpdateToLocation:(CLLocation*)newLocation
+           fromLocation:(CLLocation*)oldLocation;
 
 - (void)locationManager:(CLLocationManager*)manager
-   didFailWithError    :(NSError*)error;
+       didFailWithError:(NSError*)error;
 
 - (BOOL)isLocationServicesEnabled;
 
@@ -97,7 +97,7 @@ typedef NSUInteger CDVLocationStatus;
 - (void)stopHeading:(CDVInvokedUrlCommand*)command;
 - (void)startHeadingWithFilter:(CLLocationDegrees)filter;
 - (void)locationManager:(CLLocationManager*)manager
-   didUpdateHeading    :(CLHeading*)heading;
+       didUpdateHeading:(CLHeading*)heading;
 
 - (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager*)manager;
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m b/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m
index 07af30e..ed9ec26 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m
@@ -591,17 +591,17 @@
 - (NSString*)JSONRepresentation
 {
     return [NSString stringWithFormat:
-        @"{ timestamp: %.00f, \
+           @"{ timestamp: %.00f, \
             coords: { latitude: %f, longitude: %f, altitude: %.02f, heading: %.02f, speed: %.02f, accuracy: %.02f, altitudeAccuracy: %.02f } \
             }",
-        [self.timestamp timeIntervalSince1970] * 1000.0,
-        self.coordinate.latitude,
-        self.coordinate.longitude,
-        self.altitude,
-        self.course,
-        self.speed,
-        self.horizontalAccuracy,
-        self.verticalAccuracy
+           [self.timestamp timeIntervalSince1970] * 1000.0,
+           self.coordinate.latitude,
+           self.coordinate.longitude,
+           self.altitude,
+           self.course,
+           self.speed,
+           self.horizontalAccuracy,
+           self.verticalAccuracy
     ];
 }
 
@@ -614,9 +614,9 @@
 - (NSString*)JSONRepresentation
 {
     return [NSString stringWithFormat:
-        @"{ code: %d, message: '%@'}",
-        self.code,
-        [self localizedDescription]
+           @"{ code: %d, message: '%@'}",
+           self.code,
+           [self localizedDescription]
     ];
 }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVNotification.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVNotification.h b/lib/cordova-ios/CordovaLib/Classes/CDVNotification.h
index 1eedb54..5b5b89f 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVNotification.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVNotification.h
@@ -26,6 +26,7 @@
 
 - (void)alert:(CDVInvokedUrlCommand*)command;
 - (void)confirm:(CDVInvokedUrlCommand*)command;
+- (void)prompt:(CDVInvokedUrlCommand*)command;
 - (void)vibrate:(CDVInvokedUrlCommand*)command;
 
 @end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLib/Classes/CDVNotification.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVNotification.m b/lib/cordova-ios/CordovaLib/Classes/CDVNotification.m
index 992239e..821cb9f 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVNotification.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVNotification.m
@@ -20,12 +20,24 @@
 #import "CDVNotification.h"
 #import "NSDictionary+Extensions.h"
 
+#define DIALOG_TYPE_ALERT @"alert"
+#define DIALOG_TYPE_PROMPT @"prompt"
+
 @implementation CDVNotification
 
-- (void)showDialogWithMessage:(NSString*)message title:(NSString*)title buttons:(NSString*)buttons callbackId:(NSString*)callbackId
+/*
+ * showDialogWithMessage - Common method to instantiate the alert view for alert, confirm, and prompt notifications.
+ * Parameters:
+ *  message       The alert view message.
+ *  title         The alert view title.
+ *  buttons       The array of customized strings for the buttons.
+ *  callbackId    The commmand callback id.
+ *  dialogType    The type of alert view [alert | prompt].
+ */
+- (void)showDialogWithMessage:(NSString*)message title:(NSString*)title buttons:(NSArray*)buttons callbackId:(NSString*)callbackId dialogType:(NSString*)dialogType
 {
     CDVAlertView* alertView = [[CDVAlertView alloc]
-            initWithTitle:title
+        initWithTitle:title
                   message:message
                  delegate:self
         cancelButtonTitle:nil
@@ -33,11 +45,14 @@
 
     alertView.callbackId = callbackId;
 
-    NSArray* labels = [buttons componentsSeparatedByString:@","];
-    int count = [labels count];
+    int count = [buttons count];
 
     for (int n = 0; n < count; n++) {
-        [alertView addButtonWithTitle:[labels objectAtIndex:n]];
+        [alertView addButtonWithTitle:[buttons objectAtIndex:n]];
+    }
+
+    if ([dialogType isEqualToString:DIALOG_TYPE_PROMPT]) {
+        alertView.alertViewStyle = UIAlertViewStylePlainTextInput;
     }
 
     [alertView show];
@@ -46,52 +61,54 @@
 - (void)alert:(CDVInvokedUrlCommand*)command
 {
     NSString* callbackId = command.callbackId;
-    NSArray* arguments = command.arguments;
-    int argc = [arguments count];
-
-    NSString* message = argc > 0 ? [arguments objectAtIndex:0] : nil;
-    NSString* title = argc > 1 ? [arguments objectAtIndex:1] : nil;
-    NSString* buttons = argc > 2 ? [arguments objectAtIndex:2] : nil;
-
-    if (!title) {
-        title = NSLocalizedString(@"Alert", @"Alert");
-    }
-    if (!buttons) {
-        buttons = NSLocalizedString(@"OK", @"OK");
-    }
+    NSString* message = [command argumentAtIndex:0];
+    NSString* title = [command argumentAtIndex:1];
+    NSString* buttons = [command argumentAtIndex:2];
 
-    [self showDialogWithMessage:message title:title buttons:buttons callbackId:callbackId];
+    [self showDialogWithMessage:message title:title buttons:@[buttons] callbackId:callbackId dialogType:DIALOG_TYPE_ALERT];
 }
 
 - (void)confirm:(CDVInvokedUrlCommand*)command
 {
     NSString* callbackId = command.callbackId;
-    NSArray* arguments = command.arguments;
-    int argc = [arguments count];
+    NSString* message = [command argumentAtIndex:0];
+    NSString* title = [command argumentAtIndex:1];
+    NSArray* buttons = [command argumentAtIndex:2];
 
-    NSString* message = argc > 0 ? [arguments objectAtIndex:0] : nil;
-    NSString* title = argc > 1 ? [arguments objectAtIndex:1] : nil;
-    NSString* buttons = argc > 2 ? [arguments objectAtIndex:2] : nil;
+    [self showDialogWithMessage:message title:title buttons:buttons callbackId:callbackId dialogType:DIALOG_TYPE_ALERT];
+}
 
-    if (!title) {
-        title = NSLocalizedString(@"Confirm", @"Confirm");
-    }
-    if (!buttons) {
-        buttons = NSLocalizedString(@"OK,Cancel", @"OK,Cancel");
-    }
+- (void)prompt:(CDVInvokedUrlCommand*)command
+{
+    NSString* callbackId = command.callbackId;
+    NSString* message = [command argumentAtIndex:0];
+    NSString* title = [command argumentAtIndex:1];
+    NSArray* buttons = [command argumentAtIndex:2];
 
-    [self showDialogWithMessage:message title:title buttons:buttons callbackId:callbackId];
+    [self showDialogWithMessage:message title:title buttons:buttons callbackId:callbackId dialogType:DIALOG_TYPE_PROMPT];
 }
 
 /**
- Callback invoked when an alert dialog's buttons are clicked.
- Passes the index + label back to JS
- */
+  * Callback invoked when an alert dialog's buttons are clicked.
+  */
 - (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
 {
     CDVAlertView* cdvAlertView = (CDVAlertView*)alertView;
-    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:++buttonIndex];
-
+    CDVPluginResult* result;
+
+    // Determine what gets returned to JS based on the alert view type.
+    if (alertView.alertViewStyle == UIAlertViewStyleDefault) {
+        // For alert and confirm, return button index as int back to JS.
+        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:buttonIndex + 1];
+    } else {
+        // For prompt, return button index and input text back to JS.
+        NSString* value0 = [[alertView textFieldAtIndex:0] text];
+        NSDictionary* info = @{
+            @"buttonIndex":@(buttonIndex + 1),
+            @"input1":(value0 ? value0 : [NSNull null])
+        };
+        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:info];
+    }
     [self.commandDelegate sendPluginResult:result callbackId:cdvAlertView.callbackId];
 }
 


[08/43] Move www/ and merges/ into app/.

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/android_mdpi_portrait.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/android_mdpi_portrait.png b/templates/www/res/screen/android_mdpi_portrait.png
deleted file mode 100644
index ea15693..0000000
Binary files a/templates/www/res/screen/android_mdpi_portrait.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/android_xhdpi_landscape.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/android_xhdpi_landscape.png b/templates/www/res/screen/android_xhdpi_landscape.png
deleted file mode 100644
index 79f2f09..0000000
Binary files a/templates/www/res/screen/android_xhdpi_landscape.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/android_xhdpi_portrait.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/android_xhdpi_portrait.png b/templates/www/res/screen/android_xhdpi_portrait.png
deleted file mode 100644
index c2e8042..0000000
Binary files a/templates/www/res/screen/android_xhdpi_portrait.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/blackberry_transparent_300.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/blackberry_transparent_300.png b/templates/www/res/screen/blackberry_transparent_300.png
deleted file mode 100644
index b548bdc..0000000
Binary files a/templates/www/res/screen/blackberry_transparent_300.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/blackberry_transparent_400.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/blackberry_transparent_400.png b/templates/www/res/screen/blackberry_transparent_400.png
deleted file mode 100644
index 3facdf9..0000000
Binary files a/templates/www/res/screen/blackberry_transparent_400.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/ipad_landscape.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/ipad_landscape.png b/templates/www/res/screen/ipad_landscape.png
deleted file mode 100644
index 04be5ac..0000000
Binary files a/templates/www/res/screen/ipad_landscape.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/ipad_portrait.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/ipad_portrait.png b/templates/www/res/screen/ipad_portrait.png
deleted file mode 100644
index 41e839d..0000000
Binary files a/templates/www/res/screen/ipad_portrait.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/ipad_retina_landscape.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/ipad_retina_landscape.png b/templates/www/res/screen/ipad_retina_landscape.png
deleted file mode 100644
index 95c542d..0000000
Binary files a/templates/www/res/screen/ipad_retina_landscape.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/ipad_retina_portrait.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/ipad_retina_portrait.png b/templates/www/res/screen/ipad_retina_portrait.png
deleted file mode 100644
index aae1862..0000000
Binary files a/templates/www/res/screen/ipad_retina_portrait.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/iphone_landscape.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/iphone_landscape.png b/templates/www/res/screen/iphone_landscape.png
deleted file mode 100644
index d154883..0000000
Binary files a/templates/www/res/screen/iphone_landscape.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/iphone_portrait.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/iphone_portrait.png b/templates/www/res/screen/iphone_portrait.png
deleted file mode 100644
index 6fcba56..0000000
Binary files a/templates/www/res/screen/iphone_portrait.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/iphone_retina_landscape.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/iphone_retina_landscape.png b/templates/www/res/screen/iphone_retina_landscape.png
deleted file mode 100644
index 0165669..0000000
Binary files a/templates/www/res/screen/iphone_retina_landscape.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/iphone_retina_portrait.png
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/iphone_retina_portrait.png b/templates/www/res/screen/iphone_retina_portrait.png
deleted file mode 100644
index bd24886..0000000
Binary files a/templates/www/res/screen/iphone_retina_portrait.png and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/res/screen/windows_phone_portrait.jpg
----------------------------------------------------------------------
diff --git a/templates/www/res/screen/windows_phone_portrait.jpg b/templates/www/res/screen/windows_phone_portrait.jpg
deleted file mode 100644
index 9f95387..0000000
Binary files a/templates/www/res/screen/windows_phone_portrait.jpg and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/spec.html
----------------------------------------------------------------------
diff --git a/templates/www/spec.html b/templates/www/spec.html
deleted file mode 100644
index 83d7d2e..0000000
--- a/templates/www/spec.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<!DOCTYPE html>
-<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/740ff28d/templates/www/spec/helper.js
----------------------------------------------------------------------
diff --git a/templates/www/spec/helper.js b/templates/www/spec/helper.js
deleted file mode 100644
index 9f99445..0000000
--- a/templates/www/spec/helper.js
+++ /dev/null
@@ -1,11 +0,0 @@
-afterEach(function() {
-    document.getElementById('stage').innerHTML = '';
-});
-
-var helper = {
-    trigger: function(obj, name) {
-        var e = document.createEvent('Event');
-        e.initEvent(name, true, true);
-        obj.dispatchEvent(e);
-    }
-};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/spec/index.js
----------------------------------------------------------------------
diff --git a/templates/www/spec/index.js b/templates/www/spec/index.js
deleted file mode 100644
index 121cf63..0000000
--- a/templates/www/spec/index.js
+++ /dev/null
@@ -1,49 +0,0 @@
-describe('app', function() {
-    describe('initialize', function() {
-        it('should bind deviceready', function() {
-            runs(function() {
-                spyOn(app, 'deviceready');
-                app.initialize();
-                helper.trigger(window.document, 'deviceready');
-            });
-
-            waitsFor(function() {
-                return (app.deviceready.calls.length > 0);
-            }, 'deviceready should be called once', 500);
-
-            runs(function() {
-                expect(app.deviceready).toHaveBeenCalled();
-            });
-        });
-    });
-
-    describe('deviceready', function() {
-        it('should report that it fired', function() {
-            spyOn(app, 'report');
-            app.deviceready();
-            expect(app.report).toHaveBeenCalledWith('deviceready');
-        });
-    });
-
-    describe('report', function() {
-        beforeEach(function() {
-            var el = document.getElementById('stage');
-            el.innerHTML = ['<div id="deviceready">',
-                            '    <p class="status pending">Pending</p>',
-                            '    <p class="status complete hide">Complete</p>',
-                            '</div>'].join('\n');
-        });
-
-        it('should show the completion state', function() {
-            app.report('deviceready');
-            var el = document.querySelector('#deviceready .complete:not(.hide)');
-            expect(el).toBeTruthy();
-        });
-
-        it('should hide the pending state', function() {
-            app.report('deviceready');
-            var el = document.querySelector('#deviceready .pending.hide');
-            expect(el).toBeTruthy();
-        });
-    });
-});

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

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/spec/lib/jasmine-1.2.0/jasmine-html.js
----------------------------------------------------------------------
diff --git a/templates/www/spec/lib/jasmine-1.2.0/jasmine-html.js b/templates/www/spec/lib/jasmine-1.2.0/jasmine-html.js
deleted file mode 100644
index a0b0639..0000000
--- a/templates/www/spec/lib/jasmine-1.2.0/jasmine-html.js
+++ /dev/null
@@ -1,616 +0,0 @@
-jasmine.HtmlReporterHelpers = {};
-
-jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
-  var el = document.createElement(type);
-
-  for (var i = 2; i < arguments.length; i++) {
-    var child = arguments[i];
-
-    if (typeof child === 'string') {
-      el.appendChild(document.createTextNode(child));
-    } else {
-      if (child) {
-        el.appendChild(child);
-      }
-    }
-  }
-
-  for (var attr in attrs) {
-    if (attr == "className") {
-      el[attr] = attrs[attr];
-    } else {
-      el.setAttribute(attr, attrs[attr]);
-    }
-  }
-
-  return el;
-};
-
-jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
-  var results = child.results();
-  var status = results.passed() ? 'passed' : 'failed';
-  if (results.skipped) {
-    status = 'skipped';
-  }
-
-  return status;
-};
-
-jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
-  var parentDiv = this.dom.summary;
-  var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
-  var parent = child[parentSuite];
-
-  if (parent) {
-    if (typeof this.views.suites[parent.id] == 'undefined') {
-      this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
-    }
-    parentDiv = this.views.suites[parent.id].element;
-  }
-
-  parentDiv.appendChild(childElement);
-};
-
-
-jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
-  for(var fn in jasmine.HtmlReporterHelpers) {
-    ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
-  }
-};
-
-jasmine.HtmlReporter = function(_doc) {
-  var self = this;
-  var doc = _doc || window.document;
-
-  var reporterView;
-
-  var dom = {};
-
-  // Jasmine Reporter Public Interface
-  self.logRunningSpecs = false;
-
-  self.reportRunnerStarting = function(runner) {
-    var specs = runner.specs() || [];
-
-    if (specs.length == 0) {
-      return;
-    }
-
-    createReporterDom(runner.env.versionString());
-    doc.body.appendChild(dom.reporter);
-
-    reporterView = new jasmine.HtmlReporter.ReporterView(dom);
-    reporterView.addSpecs(specs, self.specFilter);
-  };
-
-  self.reportRunnerResults = function(runner) {
-    reporterView && reporterView.complete();
-  };
-
-  self.reportSuiteResults = function(suite) {
-    reporterView.suiteComplete(suite);
-  };
-
-  self.reportSpecStarting = function(spec) {
-    if (self.logRunningSpecs) {
-      self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
-    }
-  };
-
-  self.reportSpecResults = function(spec) {
-    reporterView.specComplete(spec);
-  };
-
-  self.log = function() {
-    var console = jasmine.getGlobal().console;
-    if (console && console.log) {
-      if (console.log.apply) {
-        console.log.apply(console, arguments);
-      } else {
-        console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
-      }
-    }
-  };
-
-  self.specFilter = function(spec) {
-    if (!focusedSpecName()) {
-      return true;
-    }
-
-    return spec.getFullName().indexOf(focusedSpecName()) === 0;
-  };
-
-  return self;
-
-  function focusedSpecName() {
-    var specName;
-
-    (function memoizeFocusedSpec() {
-      if (specName) {
-        return;
-      }
-
-      var paramMap = [];
-      var params = doc.location.search.substring(1).split('&');
-
-      for (var i = 0; i < params.length; i++) {
-        var p = params[i].split('=');
-        paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
-      }
-
-      specName = paramMap.spec;
-    })();
-
-    return specName;
-  }
-
-  function createReporterDom(version) {
-    dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
-      dom.banner = self.createDom('div', { className: 'banner' },
-        self.createDom('span', { className: 'title' }, "Jasmine "),
-        self.createDom('span', { className: 'version' }, version)),
-
-      dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
-      dom.alert = self.createDom('div', {className: 'alert'}),
-      dom.results = self.createDom('div', {className: 'results'},
-        dom.summary = self.createDom('div', { className: 'summary' }),
-        dom.details = self.createDom('div', { id: 'details' }))
-    );
-  }
-};
-jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);jasmine.HtmlReporter.ReporterView = function(dom) {
-  this.startedAt = new Date();
-  this.runningSpecCount = 0;
-  this.completeSpecCount = 0;
-  this.passedCount = 0;
-  this.failedCount = 0;
-  this.skippedCount = 0;
-
-  this.createResultsMenu = function() {
-    this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
-      this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
-      ' | ',
-      this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
-
-    this.summaryMenuItem.onclick = function() {
-      dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
-    };
-
-    this.detailsMenuItem.onclick = function() {
-      showDetails();
-    };
-  };
-
-  this.addSpecs = function(specs, specFilter) {
-    this.totalSpecCount = specs.length;
-
-    this.views = {
-      specs: {},
-      suites: {}
-    };
-
-    for (var i = 0; i < specs.length; i++) {
-      var spec = specs[i];
-      this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
-      if (specFilter(spec)) {
-        this.runningSpecCount++;
-      }
-    }
-  };
-
-  this.specComplete = function(spec) {
-    this.completeSpecCount++;
-
-    if (isUndefined(this.views.specs[spec.id])) {
-      this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
-    }
-
-    var specView = this.views.specs[spec.id];
-
-    switch (specView.status()) {
-      case 'passed':
-        this.passedCount++;
-        break;
-
-      case 'failed':
-        this.failedCount++;
-        break;
-
-      case 'skipped':
-        this.skippedCount++;
-        break;
-    }
-
-    specView.refresh();
-    this.refresh();
-  };
-
-  this.suiteComplete = function(suite) {
-    var suiteView = this.views.suites[suite.id];
-    if (isUndefined(suiteView)) {
-      return;
-    }
-    suiteView.refresh();
-  };
-
-  this.refresh = function() {
-
-    if (isUndefined(this.resultsMenu)) {
-      this.createResultsMenu();
-    }
-
-    // currently running UI
-    if (isUndefined(this.runningAlert)) {
-      this.runningAlert = this.createDom('a', {href: "?", className: "runningAlert bar"});
-      dom.alert.appendChild(this.runningAlert);
-    }
-    this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
-
-    // skipped specs UI
-    if (isUndefined(this.skippedAlert)) {
-      this.skippedAlert = this.createDom('a', {href: "?", className: "skippedAlert bar"});
-    }
-
-    this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
-
-    if (this.skippedCount === 1 && isDefined(dom.alert)) {
-      dom.alert.appendChild(this.skippedAlert);
-    }
-
-    // passing specs UI
-    if (isUndefined(this.passedAlert)) {
-      this.passedAlert = this.createDom('span', {href: "?", className: "passingAlert bar"});
-    }
-    this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
-
-    // failing specs UI
-    if (isUndefined(this.failedAlert)) {
-      this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
-    }
-    this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
-
-    if (this.failedCount === 1 && isDefined(dom.alert)) {
-      dom.alert.appendChild(this.failedAlert);
-      dom.alert.appendChild(this.resultsMenu);
-    }
-
-    // summary info
-    this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
-    this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
-  };
-
-  this.complete = function() {
-    dom.alert.removeChild(this.runningAlert);
-
-    this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
-
-    if (this.failedCount === 0) {
-      dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
-    } else {
-      showDetails();
-    }
-
-    dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
-  };
-
-  return this;
-
-  function showDetails() {
-    if (dom.reporter.className.search(/showDetails/) === -1) {
-      dom.reporter.className += " showDetails";
-    }
-  }
-
-  function isUndefined(obj) {
-    return typeof obj === 'undefined';
-  }
-
-  function isDefined(obj) {
-    return !isUndefined(obj);
-  }
-
-  function specPluralizedFor(count) {
-    var str = count + " spec";
-    if (count > 1) {
-      str += "s"
-    }
-    return str;
-  }
-
-};
-
-jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
-
-
-jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
-  this.spec = spec;
-  this.dom = dom;
-  this.views = views;
-
-  this.symbol = this.createDom('li', { className: 'pending' });
-  this.dom.symbolSummary.appendChild(this.symbol);
-
-  this.summary = this.createDom('div', { className: 'specSummary' },
-      this.createDom('a', {
-        className: 'description',
-        href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
-        title: this.spec.getFullName()
-      }, this.spec.description)
-  );
-
-  this.detail = this.createDom('div', { className: 'specDetail' },
-      this.createDom('a', {
-        className: 'description',
-        href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
-        title: this.spec.getFullName()
-      }, this.spec.getFullName())
-  );
-};
-
-jasmine.HtmlReporter.SpecView.prototype.status = function() {
-  return this.getSpecStatus(this.spec);
-};
-
-jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
-  this.symbol.className = this.status();
-
-  switch (this.status()) {
-    case 'skipped':
-      break;
-
-    case 'passed':
-      this.appendSummaryToSuiteDiv();
-      break;
-
-    case 'failed':
-      this.appendSummaryToSuiteDiv();
-      this.appendFailureDetail();
-      break;
-  }
-};
-
-jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
-  this.summary.className += ' ' + this.status();
-  this.appendToSummary(this.spec, this.summary);
-};
-
-jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
-  this.detail.className += ' ' + this.status();
-
-  var resultItems = this.spec.results().getItems();
-  var messagesDiv = this.createDom('div', { className: 'messages' });
-
-  for (var i = 0; i < resultItems.length; i++) {
-    var result = resultItems[i];
-
-    if (result.type == 'log') {
-      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
-    } else if (result.type == 'expect' && result.passed && !result.passed()) {
-      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
-
-      if (result.trace.stack) {
-        messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
-      }
-    }
-  }
-
-  if (messagesDiv.childNodes.length > 0) {
-    this.detail.appendChild(messagesDiv);
-    this.dom.details.appendChild(this.detail);
-  }
-};
-
-jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
-  this.suite = suite;
-  this.dom = dom;
-  this.views = views;
-
-  this.element = this.createDom('div', { className: 'suite' },
-      this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description)
-  );
-
-  this.appendToSummary(this.suite, this.element);
-};
-
-jasmine.HtmlReporter.SuiteView.prototype.status = function() {
-  return this.getSpecStatus(this.suite);
-};
-
-jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
-  this.element.className += " " + this.status();
-};
-
-jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
-
-/* @deprecated Use jasmine.HtmlReporter instead
- */
-jasmine.TrivialReporter = function(doc) {
-  this.document = doc || document;
-  this.suiteDivs = {};
-  this.logRunningSpecs = false;
-};
-
-jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
-  var el = document.createElement(type);
-
-  for (var i = 2; i < arguments.length; i++) {
-    var child = arguments[i];
-
-    if (typeof child === 'string') {
-      el.appendChild(document.createTextNode(child));
-    } else {
-      if (child) { el.appendChild(child); }
-    }
-  }
-
-  for (var attr in attrs) {
-    if (attr == "className") {
-      el[attr] = attrs[attr];
-    } else {
-      el.setAttribute(attr, attrs[attr]);
-    }
-  }
-
-  return el;
-};
-
-jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
-  var showPassed, showSkipped;
-
-  this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
-      this.createDom('div', { className: 'banner' },
-        this.createDom('div', { className: 'logo' },
-            this.createDom('span', { className: 'title' }, "Jasmine"),
-            this.createDom('span', { className: 'version' }, runner.env.versionString())),
-        this.createDom('div', { className: 'options' },
-            "Show ",
-            showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
-            this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
-            showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
-            this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
-            )
-          ),
-
-      this.runnerDiv = this.createDom('div', { className: 'runner running' },
-          this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
-          this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
-          this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
-      );
-
-  this.document.body.appendChild(this.outerDiv);
-
-  var suites = runner.suites();
-  for (var i = 0; i < suites.length; i++) {
-    var suite = suites[i];
-    var suiteDiv = this.createDom('div', { className: 'suite' },
-        this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
-        this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
-    this.suiteDivs[suite.id] = suiteDiv;
-    var parentDiv = this.outerDiv;
-    if (suite.parentSuite) {
-      parentDiv = this.suiteDivs[suite.parentSuite.id];
-    }
-    parentDiv.appendChild(suiteDiv);
-  }
-
-  this.startedAt = new Date();
-
-  var self = this;
-  showPassed.onclick = function(evt) {
-    if (showPassed.checked) {
-      self.outerDiv.className += ' show-passed';
-    } else {
-      self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
-    }
-  };
-
-  showSkipped.onclick = function(evt) {
-    if (showSkipped.checked) {
-      self.outerDiv.className += ' show-skipped';
-    } else {
-      self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
-    }
-  };
-};
-
-jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
-  var results = runner.results();
-  var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
-  this.runnerDiv.setAttribute("class", className);
-  //do it twice for IE
-  this.runnerDiv.setAttribute("className", className);
-  var specs = runner.specs();
-  var specCount = 0;
-  for (var i = 0; i < specs.length; i++) {
-    if (this.specFilter(specs[i])) {
-      specCount++;
-    }
-  }
-  var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
-  message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
-  this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
-
-  this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
-};
-
-jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
-  var results = suite.results();
-  var status = results.passed() ? 'passed' : 'failed';
-  if (results.totalCount === 0) { // todo: change this to check results.skipped
-    status = 'skipped';
-  }
-  this.suiteDivs[suite.id].className += " " + status;
-};
-
-jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
-  if (this.logRunningSpecs) {
-    this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
-  }
-};
-
-jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
-  var results = spec.results();
-  var status = results.passed() ? 'passed' : 'failed';
-  if (results.skipped) {
-    status = 'skipped';
-  }
-  var specDiv = this.createDom('div', { className: 'spec '  + status },
-      this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
-      this.createDom('a', {
-        className: 'description',
-        href: '?spec=' + encodeURIComponent(spec.getFullName()),
-        title: spec.getFullName()
-      }, spec.description));
-
-
-  var resultItems = results.getItems();
-  var messagesDiv = this.createDom('div', { className: 'messages' });
-  for (var i = 0; i < resultItems.length; i++) {
-    var result = resultItems[i];
-
-    if (result.type == 'log') {
-      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
-    } else if (result.type == 'expect' && result.passed && !result.passed()) {
-      messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
-
-      if (result.trace.stack) {
-        messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
-      }
-    }
-  }
-
-  if (messagesDiv.childNodes.length > 0) {
-    specDiv.appendChild(messagesDiv);
-  }
-
-  this.suiteDivs[spec.suite.id].appendChild(specDiv);
-};
-
-jasmine.TrivialReporter.prototype.log = function() {
-  var console = jasmine.getGlobal().console;
-  if (console && console.log) {
-    if (console.log.apply) {
-      console.log.apply(console, arguments);
-    } else {
-      console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
-    }
-  }
-};
-
-jasmine.TrivialReporter.prototype.getLocation = function() {
-  return this.document.location;
-};
-
-jasmine.TrivialReporter.prototype.specFilter = function(spec) {
-  var paramMap = {};
-  var params = this.getLocation().search.substring(1).split('&');
-  for (var i = 0; i < params.length; i++) {
-    var p = params[i].split('=');
-    paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
-  }
-
-  if (!paramMap.spec) {
-    return true;
-  }
-  return spec.getFullName().indexOf(paramMap.spec) === 0;
-};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/www/spec/lib/jasmine-1.2.0/jasmine.css
----------------------------------------------------------------------
diff --git a/templates/www/spec/lib/jasmine-1.2.0/jasmine.css b/templates/www/spec/lib/jasmine-1.2.0/jasmine.css
deleted file mode 100644
index 826e575..0000000
--- a/templates/www/spec/lib/jasmine-1.2.0/jasmine.css
+++ /dev/null
@@ -1,81 +0,0 @@
-body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
-
-#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
-#HTMLReporter a { text-decoration: none; }
-#HTMLReporter a:hover { text-decoration: underline; }
-#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
-#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
-#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
-#HTMLReporter .version { color: #aaaaaa; }
-#HTMLReporter .banner { margin-top: 14px; }
-#HTMLReporter .duration { color: #aaaaaa; float: right; }
-#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
-#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
-#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
-#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
-#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
-#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
-#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
-#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
-#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
-#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
-#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
-#HTMLReporter .runningAlert { background-color: #666666; }
-#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
-#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
-#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
-#HTMLReporter .passingAlert { background-color: #a6b779; }
-#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
-#HTMLReporter .failingAlert { background-color: #cf867e; }
-#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
-#HTMLReporter .results { margin-top: 14px; }
-#HTMLReporter #details { display: none; }
-#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
-#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
-#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
-#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
-#HTMLReporter.showDetails .summary { display: none; }
-#HTMLReporter.showDetails #details { display: block; }
-#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
-#HTMLReporter .summary { margin-top: 14px; }
-#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
-#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
-#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
-#HTMLReporter .description + .suite { margin-top: 0; }
-#HTMLReporter .suite { margin-top: 14px; }
-#HTMLReporter .suite a { color: #333333; }
-#HTMLReporter #details .specDetail { margin-bottom: 28px; }
-#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
-#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
-#HTMLReporter .resultMessage span.result { display: block; }
-#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
-
-#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
-#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
-#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
-#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
-#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
-#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
-#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
-#TrivialReporter .runner.running { background-color: yellow; }
-#TrivialReporter .options { text-align: right; font-size: .8em; }
-#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
-#TrivialReporter .suite .suite { margin: 5px; }
-#TrivialReporter .suite.passed { background-color: #dfd; }
-#TrivialReporter .suite.failed { background-color: #fdd; }
-#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
-#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
-#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
-#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
-#TrivialReporter .spec.skipped { background-color: #bbb; }
-#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
-#TrivialReporter .passed { background-color: #cfc; display: none; }
-#TrivialReporter .failed { background-color: #fbb; }
-#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
-#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
-#TrivialReporter .resultMessage .mismatch { color: black; }
-#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
-#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
-#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
-#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
-#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }


[30/43] git commit: CB-3183 handle missing plugins directory

Posted by an...@apache.org.
CB-3183 handle missing plugins directory


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

Branch: refs/heads/master
Commit: d27766874ac653fdf90a102a6314520135ecb395
Parents: ee26ee9
Author: Don Coleman <dc...@chariotsolutions.com>
Authored: Thu Apr 18 23:44:19 2013 -0400
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu May 9 15:03:56 2013 -0700

----------------------------------------------------------------------
 spec/plugin.spec.js |   26 ++++++++++++
 src/plugin.js       |   95 ++++++++++++++++++++++++++++------------------
 src/util.js         |   21 ++++++----
 3 files changed, 97 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d2776687/spec/plugin.spec.js
----------------------------------------------------------------------
diff --git a/spec/plugin.spec.js b/spec/plugin.spec.js
index 12d893c..a23f9f9 100644
--- a/spec/plugin.spec.js
+++ b/spec/plugin.spec.js
@@ -61,6 +61,32 @@ describe('plugin command', function() {
         }).toThrow();
     });
 
+    describe('edge cases', function() {
+       beforeEach(function() {
+           cordova.create(tempDir);
+           process.chdir(tempDir);
+       });
+
+       afterEach(function() {
+           process.chdir(cwd);
+       });
+
+       it('should not fail when the plugins directory is missing', function() {
+           fs.rmdirSync('plugins');
+
+           expect(function() {
+               cordova.plugin();
+           }).not.toThrow();
+       });
+
+       it('should ignore files, like .gitignore, in the plugins directory', function() {
+           var someFile = path.join(tempDir, 'plugins', '.gitignore');
+           fs.writeFileSync(someFile, 'not a plugin');
+
+           expect(cordova.plugin('list')).toEqual('No plugins added. Use `cordova plugin add <plugin>`.');
+       });
+    });
+
     describe('`ls`', function() {
         beforeEach(function() {
             cordova.create(tempDir);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d2776687/src/plugin.js
----------------------------------------------------------------------
diff --git a/src/plugin.js b/src/plugin.js
index 355157d..8997f97 100644
--- a/src/plugin.js
+++ b/src/plugin.js
@@ -24,15 +24,10 @@ var cordova_util  = require('./util'),
     shell         = require('shelljs'),
     config_parser = require('./config_parser'),
     hooker        = require('./hooker'),
+    core_platforms= require('../platforms'),
+    platform      = require('./platform'),
     plugin_parser = require('./plugin_parser'),
-    ls            = fs.readdirSync,
-    plugman       = require('plugman');
-
-var parsers = {
-    "android": require('./metadata/android_parser'),
-    "ios": require('./metadata/ios_parser'),
-    "blackberry": require('./metadata/blackberry_parser')
-};
+    ls            = fs.readdirSync;
 
 module.exports = function plugin(command, targets, callback) {
     var projectRoot = cordova_util.isCordova(process.cwd());
@@ -44,23 +39,22 @@ module.exports = function plugin(command, targets, callback) {
 
     var hooks = new hooker(projectRoot);
 
+    var projectWww = path.join(projectRoot, 'www');
+
     // Grab config info for the project
-    var xml = cordova_util.projectConfig(projectRoot);
+    var xml = path.join(projectWww, 'config.xml');
     var cfg = new config_parser(xml);
     var platforms = cordova_util.listPlatforms(projectRoot);
 
     // Massage plugin name(s) / path(s)
     var pluginPath, plugins, names = [];
     pluginPath = path.join(projectRoot, 'plugins');
-    plugins = ls(pluginPath);
-    if (targets) {
+    plugins = cordova_util.findPlugins(pluginPath);
+    if (targets) { 
         if (!(targets instanceof Array)) targets = [targets];
         targets.forEach(function(target) {
-            if (target[target.length - 1] == path.sep) {
-                target = target.substring(0, target.length - 1);
-            }
-
-            var targetName = target.substr(target.lastIndexOf(path.sep) + 1);
+            var targetName = target.substr(target.lastIndexOf('/') + 1);
+            if (targetName[targetName.length-1] == '/') targetName = targetName.substr(0, targetName.length-1);
             names.push(targetName);
         });
     }
@@ -76,25 +70,52 @@ module.exports = function plugin(command, targets, callback) {
             } else return 'No plugins added. Use `cordova plugin add <plugin>`.';
             break;
         case 'add':
+            if (platforms.length === 0) {
+                throw new Error('You need at least one platform added to your app. Use `cordova platform add <platform>`.');
+            }
             targets.forEach(function(target, index) {
-                hooks.fire('before_plugin_add');
-                var pluginsDir = path.join(projectRoot, 'plugins');
+                var pluginContents = ls(target);
+                var targetName = names[index];
+                // Check if we already have the plugin.
+                // TODO edge case: if a new platform is added, then you want
+                // to re-add the plugin to the new platform.
+                if (plugins.indexOf(targetName) > -1) {
+                    throw new Error('Plugin "' + targetName + '" already added to project.');
+                }
+                // Check if the plugin has a plugin.xml in the root of the
+                // specified dir.
+                if (pluginContents.indexOf('plugin.xml') == -1) {
+                    throw new Error('Plugin "' + targetName + '" does not have a plugin.xml in the root. Plugin must support the Cordova Plugin Specification: https://github.com/alunny/cordova-plugin-spec');
+                }
 
-                if (target[target.length - 1] == path.sep) {
-                    target = target.substring(0, target.length - 1);
+                // Check if there is at least one match between plugin
+                // supported platforms and app platforms
+                var pluginXml = new plugin_parser(path.join(target, 'plugin.xml'));
+                var intersection = pluginXml.platforms.filter(function(e) {
+                    if (platforms.indexOf(e) == -1) return false;
+                    else return true;
+                });
+                if (intersection.length === 0) {
+                    throw new Error('Plugin "' + targetName + '" does not support any of your application\'s platforms. Plugin platforms: ' + pluginXml.platforms.join(', ') + '; your application\'s platforms: ' + platforms.join(', '));
                 }
 
-                // Fetch the plugin first.
-                plugman.fetch(target, pluginsDir, false);
-                
-                // Iterate over all platforms in the project and install the plugin.
-                platforms.forEach(function(platform) {
-                    var platformRoot = path.join(projectRoot, 'platforms', platform);
-                    var parser = new parsers[platform](platformRoot);
-                    plugman.install(platform, platformRoot,
-                                    names[index], pluginsDir, {}, parser.staging_dir());
+                hooks.fire('before_plugin_add');
+
+                var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'plugman.js');
+
+                // Iterate over all matchin app-plugin platforms in the project and install the
+                // plugin.
+                intersection.forEach(function(platform) {
+                    var cmd = util.format('%s --platform %s --project "%s" --plugin "%s"', cli, platform, path.join(projectRoot, 'platforms', platform), target);
+                    var plugin_cli = shell.exec(cmd, {silent:true});
+                    if (plugin_cli.code > 0) throw new Error('An error occured during plugin installation for ' + platform + '. ' + plugin_cli.output);
                 });
 
+                // Finally copy the plugin into the project
+                var targetPath = path.join(pluginPath, targetName);
+                shell.mkdir('-p', targetPath);
+                shell.cp('-r', path.join(target, '*'), targetPath);
+
                 hooks.fire('after_plugin_add');
             });
             if (callback) callback();
@@ -110,6 +131,8 @@ module.exports = function plugin(command, targets, callback) {
                 if (plugins.indexOf(targetName) > -1) {
                     var targetPath = path.join(pluginPath, targetName);
                     hooks.fire('before_plugin_rm');
+                    var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'plugman.js');
+
                     // Check if there is at least one match between plugin
                     // supported platforms and app platforms
                     var pluginXml = new plugin_parser(path.join(targetPath, 'plugin.xml'));
@@ -118,18 +141,16 @@ module.exports = function plugin(command, targets, callback) {
                         else return true;
                     });
 
-                    // Iterate over all the common platforms between the plugin
-                    // and the app, and uninstall.
-                    // If this is a web-only plugin with no platform tags, this step
-                    // is not needed and we just --remove the plugin below.
+                    // Iterate over all matchin app-plugin platforms in the project and uninstall the
+                    // plugin.
                     intersection.forEach(function(platform) {
-                        var platformRoot = path.join(projectRoot, 'platforms', platform);
-                        var parser = new parsers[platform](platformRoot);
-                        plugman.uninstall(platform, platformRoot, targetName, path.join(projectRoot, 'plugins'), {}, parser.staging_dir());
+                        var cmd = util.format('%s --platform %s --project "%s" --plugin "%s" --remove', cli, platform, path.join(projectRoot, 'platforms', platform), targetPath);
+                        var plugin_cli = shell.exec(cmd, {silent:true});
+                        if (plugin_cli.code > 0) throw new Error('An error occured during plugin uninstallation for ' + platform + '. ' + plugin_cli.output);
                     });
 
                     // Finally remove the plugin dir from plugins/
-                    plugman.remove(targetName, path.join(projectRoot, 'plugins'));
+                    shell.rm('-rf', targetPath);
 
                     hooks.fire('after_plugin_rm');
                 } else {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d2776687/src/util.js
----------------------------------------------------------------------
diff --git a/src/util.js b/src/util.js
index 4620e03..7ebbb17 100644
--- a/src/util.js
+++ b/src/util.js
@@ -63,13 +63,18 @@ module.exports = {
             return core_platforms.indexOf(p) > -1;
         });
     },
-    projectWww: function(projectDir) {
-        return path.join(projectDir, 'app', 'www');
-    },
-    appDir: function(projectDir) {
-        return path.join(projectDir, 'app');
-    },
-    projectConfig: function(projectDir) {
-        return path.join(projectDir, 'app', 'config.xml');
+    // list the directories in the path, ignoring any files
+    findPlugins:function(pluginPath) {
+        var plugins = [],
+            stats;
+
+        if (fs.existsSync(pluginPath)) {
+            plugins = fs.readdirSync(pluginPath).filter(function (fileName) {
+               stats = fs.statSync(path.join(pluginPath, fileName));
+               return stats.isDirectory();
+            });
+        }
+
+        return plugins;
     }
 };


[39/43] git commit: [CB-3238] Update cordova-android to 2.7.0

Posted by an...@apache.org.
[CB-3238] Update cordova-android to 2.7.0


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

Branch: refs/heads/master
Commit: ee0a5029eeefeebe9d31055bf73ae18926fa9f94
Parents: 0f619a7
Author: Michael Brooks <mi...@michaelbrooks.ca>
Authored: Tue Apr 30 13:27:04 2013 -0700
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu May 9 15:56:00 2013 -0700

----------------------------------------------------------------------
 lib/cordova-android/VERSION                        |    2 +-
 lib/cordova-android/bin/check_reqs.bat             |    9 -
 lib/cordova-android/bin/check_reqs.js              |   81 --
 lib/cordova-android/bin/create                     |   11 +-
 lib/cordova-android/bin/create.bat                 |   34 +-
 lib/cordova-android/bin/create.js                  |   81 +--
 lib/cordova-android/bin/templates/cordova/build    |    5 +-
 .../bin/templates/cordova/build.bat                |   20 +-
 lib/cordova-android/bin/templates/cordova/clean    |    5 +-
 .../bin/templates/cordova/clean.bat                |   20 +-
 lib/cordova-android/bin/templates/cordova/cordova  |  159 ++++
 .../bin/templates/cordova/cordova.bat              |    7 +-
 .../bin/templates/cordova/cordova.js               |  137 ++++
 .../bin/templates/cordova/lib/cordova              |  386 ----------
 .../bin/templates/cordova/lib/cordova.js           |  593 ---------------
 .../bin/templates/cordova/lib/install-device       |   23 -
 .../bin/templates/cordova/lib/install-device.bat   |    9 -
 .../bin/templates/cordova/lib/install-emulator     |   23 -
 .../bin/templates/cordova/lib/install-emulator.bat |    9 -
 .../bin/templates/cordova/lib/list-devices         |   23 -
 .../bin/templates/cordova/lib/list-devices.bat     |    9 -
 .../bin/templates/cordova/lib/list-emulator-images |   23 -
 .../templates/cordova/lib/list-emulator-images.bat |    9 -
 .../templates/cordova/lib/list-started-emulators   |   23 -
 .../cordova/lib/list-started-emulators.bat         |    9 -
 .../bin/templates/cordova/lib/start-emulator       |   23 -
 .../bin/templates/cordova/lib/start-emulator.bat   |    9 -
 lib/cordova-android/bin/templates/cordova/log      |    5 +-
 lib/cordova-android/bin/templates/cordova/log.bat  |   20 +-
 lib/cordova-android/bin/templates/cordova/release  |   24 +
 lib/cordova-android/bin/templates/cordova/run      |    5 +-
 lib/cordova-android/bin/templates/cordova/run.bat  |    3 +-
 .../bin/templates/project/assets/www/index.html    |    2 +-
 lib/cordova-android/bin/update                     |   11 +-
 lib/cordova-android/bin/update.js                  |    8 +-
 .../framework/assets/js/cordova.android.js         |    6 +-
 .../framework/assets/www/index.html                |    2 +-
 .../framework/src/org/apache/cordova/Device.java   |    2 +-
 .../cordova/IceCreamCordovaWebViewClient.java      |   11 +-
 .../src/org/apache/cordova/api/PluginManager.java  |    1 -
 40 files changed, 443 insertions(+), 1399 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-android/VERSION b/lib/cordova-android/VERSION
index e70b452..24ba9a3 100644
--- a/lib/cordova-android/VERSION
+++ b/lib/cordova-android/VERSION
@@ -1 +1 @@
-2.6.0
+2.7.0

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/check_reqs.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/check_reqs.bat b/lib/cordova-android/bin/check_reqs.bat
deleted file mode 100644
index 65514c8..0000000
--- a/lib/cordova-android/bin/check_reqs.bat
+++ /dev/null
@@ -1,9 +0,0 @@
-@ECHO OFF
-SET full_path=%~dp0
-IF EXIST %full_path%check_reqs.js (
-        cscript "%full_path%check_reqs.js" //nologo
-) ELSE (
-    ECHO.
-    ECHO ERROR: Could not find 'check_reqs.js' in 'bin' folder, aborting...>&2
-    EXIT /B 1
-)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/check_reqs.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/check_reqs.js b/lib/cordova-android/bin/check_reqs.js
deleted file mode 100644
index ef30991..0000000
--- a/lib/cordova-android/bin/check_reqs.js
+++ /dev/null
@@ -1,81 +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 ROOT  = WScript.ScriptFullName.split('\\bin\\check_reqs.js').join(''),
-    shell = WScript.CreateObject("WScript.Shell"),
-    fso   = WScript.CreateObject('Scripting.FileSystemObject');
-
-
-// executes a command in the shell, returns stdout or stderr if error
-function exec_out(command) {
-    var oExec=shell.Exec(command);
-    var output = new String();
-    while (oExec.Status == 0) {
-        if (!oExec.StdOut.AtEndOfStream) {
-            var line = oExec.StdOut.ReadAll();
-            // XXX: Change to verbose mode 
-            // WScript.StdOut.WriteLine(line);
-            output += line;
-        }
-        WScript.sleep(100);
-    }
-    //Check to make sure our scripts did not encounter an error
-    if (!oExec.StdErr.AtEndOfStream) {
-        var line = oExec.StdErr.ReadAll();
-        return {'error' : true, 'output' : line};
-    } else if (!oExec.StdOut.AtEndOfStream) {
-            var line = oExec.StdOut.ReadAll();
-            // XXX: Change to verbose mode 
-            // WScript.StdOut.WriteLine(line);
-            output += line;
-    }
-    return {'error' : false, 'output' : output};
-}
-
-// log to stdout or stderr
-function Log(msg, error) {
-    if (error) {
-        WScript.StdErr.WriteLine(msg);
-    }
-    else {
-        WScript.StdOut.WriteLine(msg);
-    }
-} 
-
-// checks that android requirements are met
-function check_requirements() {
-    var result = exec_out('%comspec% /c android list target');
-    if(result.error) {
-        Log('The command `android` failed. Make sure you have the latest Android SDK installed, and the `android` command (inside the tools/ folder) added to your path. Output: ' + result.output, true);
-        WScript.Quit(2);
-    }
-    else if(!result.output.match(/android[-]17/)) {
-        Log('Please install Android target 17 (the Android 4.2 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.', true);
-        Log('Output : ' + result.output);
-        WScript.Quit(2);
-    }
-    else {
-        var cmd = '%comspec% /c android update project -p ' + ROOT + '\\framework -t android-17';
-        result = exec_out(cmd);
-        if(result.error) {
-            Log('Error updating the Cordova library to work with your Android environment. Command run: "' + cmd + '", output: ' + result.output, true);
-            WScript.Quit(2);  
-        }
-    }
-}
-
-check_requirements();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/create
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/create b/lib/cordova-android/bin/create
index b7e96b4..35d3363 100755
--- a/lib/cordova-android/bin/create
+++ b/lib/cordova-android/bin/create
@@ -161,18 +161,11 @@ replace "s/__APILEVEL__/${API_LEVEL}/g" "$MANIFEST_PATH"
 
 # creating cordova folder and copying run/build/log/launch scripts
 mkdir "$PROJECT_PATH"/cordova
-mkdir "$PROJECT_PATH"/cordova/lib
 createAppInfoJar
 cp "$BUILD_PATH"/bin/templates/cordova/appinfo.jar "$PROJECT_PATH"/cordova/appinfo.jar
+cp "$BUILD_PATH"/bin/templates/cordova/cordova "$PROJECT_PATH"/cordova/cordova
 cp "$BUILD_PATH"/bin/templates/cordova/build "$PROJECT_PATH"/cordova/build
+cp "$BUILD_PATH"/bin/templates/cordova/release "$PROJECT_PATH"/cordova/release
 cp "$BUILD_PATH"/bin/templates/cordova/clean "$PROJECT_PATH"/cordova/clean
 cp "$BUILD_PATH"/bin/templates/cordova/log "$PROJECT_PATH"/cordova/log
 cp "$BUILD_PATH"/bin/templates/cordova/run "$PROJECT_PATH"/cordova/run
-cp "$BUILD_PATH"/bin/templates/cordova/lib/cordova "$PROJECT_PATH"/cordova/lib/cordova
-cp "$BUILD_PATH"/bin/templates/cordova/lib/install-device "$PROJECT_PATH"/cordova/lib/install-device
-cp "$BUILD_PATH"/bin/templates/cordova/lib/install-emulator "$PROJECT_PATH"/cordova/lib/install-emulator
-cp "$BUILD_PATH"/bin/templates/cordova/lib/list-devices "$PROJECT_PATH"/cordova/lib/list-devices
-cp "$BUILD_PATH"/bin/templates/cordova/lib/list-emulator-images "$PROJECT_PATH"/cordova/lib/list-emulator-images
-cp "$BUILD_PATH"/bin/templates/cordova/lib/list-started-emulators "$PROJECT_PATH"/cordova/lib/list-started-emulators
-cp "$BUILD_PATH"/bin/templates/cordova/lib/start-emulator "$PROJECT_PATH"/cordova/lib/start-emulator
-

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/create.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/create.bat b/lib/cordova-android/bin/create.bat
index 7f0346f..cdbd611 100644
--- a/lib/cordova-android/bin/create.bat
+++ b/lib/cordova-android/bin/create.bat
@@ -1,5 +1,3 @@
-@ECHO OFF
-GOTO BEGIN
 :: 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
@@ -17,23 +15,23 @@ GOTO BEGIN
 :: specific language governing permissions and limitations
 :: under the License.
 
-:BEGIN
-        IF NOT DEFINED JAVA_HOME GOTO MISSING_JAVA_HOME
+@ECHO OFF
+IF NOT DEFINED JAVA_HOME GOTO MISSING_JAVA_HOME
 
-        FOR %%X in (java.exe javac.exe ant.bat android.bat) do (
-            IF [%%~$PATH:X]==[] (
-              ECHO Cannot locate %%X using the PATH environment variable.
-              ECHO Retry after adding directory containing %%X to the PATH variable.
-              ECHO Remember to open a new command window after updating the PATH variable.
-              IF "%%X"=="java.exe" GOTO GET_JAVA
-              IF "%%X"=="javac.exe" GOTO GET_JAVA
-              IF "%%X"=="ant.bat" GOTO GET_ANT
-              IF "%%X"=="android.bat" GOTO GET_ANDROID
-              GOTO ERROR
-            )
-        )
-        cscript "%~dp0\create.js" %* //nologo
-        GOTO END
+FOR %%X in (java.exe javac.exe ant.bat android.bat) do (
+    IF [%%~$PATH:X]==[] (
+      ECHO Cannot locate %%X using the PATH environment variable.
+      ECHO Retry after adding directory containing %%X to the PATH variable.
+      ECHO Remember to open a new command window after updating the PATH variable.
+      IF "%%X"=="java.exe" GOTO GET_JAVA
+      IF "%%X"=="javac.exe" GOTO GET_JAVA
+      IF "%%X"=="ant.bat" GOTO GET_ANT
+      IF "%%X"=="android.bat" GOTO GET_ANDROID
+      GOTO ERROR
+    )
+)
+cscript "%~dp0\create.js" %*
+GOTO END
 :MISSING_JAVA_HOME
         ECHO The JAVA_HOME environment variable is not set.
         ECHO Set JAVA_HOME to an existing JRE directory.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/create.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/create.js b/lib/cordova-android/bin/create.js
index 5176b7d..d0d9999 100644
--- a/lib/cordova-android/bin/create.js
+++ b/lib/cordova-android/bin/create.js
@@ -24,30 +24,7 @@
  *  ./create [path package activity]
  */
 
-var args = WScript.Arguments, PROJECT_PATH="example", 
-    PACKAGE="org.apache.cordova.example", ACTIVITY="cordovaExample",
-    shell=WScript.CreateObject("WScript.Shell"),
-    fso = WScript.CreateObject('Scripting.FileSystemObject');
-
-function Usage() {
-    Log("Usage: create PathTONewProject [ PackageName AppName ]");
-    Log("    PathTONewProject : The path to where you wish to create the project");
-    Log("    PackageName      : The package for the project (default is org.apache.cordova.example)")
-    Log("    AppName          : The name of the application/activity (default is cordovaExample)");
-    Log("examples:");
-    Log("    create C:\\Users\\anonymous\\Desktop\\MyProject");
-    Log("    create C:\\Users\\anonymous\\Desktop\\MyProject io.Cordova.Example AnApp");
-}
-
-// logs messaged to stdout and stderr
-function Log(msg, error) {
-    if (error) {
-        WScript.StdErr.WriteLine(msg);
-    }
-    else {
-        WScript.StdOut.WriteLine(msg);
-    }
-}
+var fso = WScript.CreateObject('Scripting.FileSystemObject');
 
 function read(filename) {
     var fso=WScript.CreateObject("Scripting.FileSystemObject");
@@ -59,7 +36,7 @@ function read(filename) {
 
 function checkTargets(targets) {
     if(!targets) {
-        Log("You do not have any android targets setup. Please create at least one target with the `android` command", true);
+        WScript.Echo("You do not have any android targets setup. Please create at least one target with the `android` command");
         WScript.Quit(69);
     }
 }
@@ -97,7 +74,7 @@ function exec(command) {
 
 function createAppInfoJar() {
     if(!fso.FileExists(ROOT+"\\bin\\templates\\cordova\\appinfo.jar")) {
-        Log("Creating appinfo.jar...");
+        WScript.Echo("Creating appinfo.jar...");
         var cur = shell.CurrentDirectory;
         shell.CurrentDirectory = ROOT+"\\bin\\templates\\cordova\\ApplicationInfo";
         exec("javac ApplicationInfo.java");
@@ -143,7 +120,7 @@ function downloadCommonsCodec() {
           stream.SaveToFile(savePath);
           stream.Close();
         } else {
-          Log('Could not retrieve the commons-codec. Please download it yourself and put into the framework/libs directory. This process may fail now. Sorry.');
+          WScript.Echo('Could not retrieve the commons-codec. Please download it yourself and put into the framework/libs directory. This process may fail now. Sorry.');
         }
       }
       var app = WScript.CreateObject('Shell.Application');
@@ -159,34 +136,23 @@ function downloadCommonsCodec() {
       fso.DeleteFolder(ROOT + '\\framework\\libs\\commons-codec-1.7', true);
     }
 }
+
+var args = WScript.Arguments, PROJECT_PATH="example", 
+    PACKAGE="org.apache.cordova.example", ACTIVITY="cordovaExample",
+    shell=WScript.CreateObject("WScript.Shell");
     
 // working dir
 var ROOT = WScript.ScriptFullName.split('\\bin\\create.js').join('');
-if (args.Count() > 0) {
-    // support help flags
-    if (args(0) == "--help" || args(0) == "/?" ||
-            args(0) == "help" || args(0) == "-help" || args(0) == "/help" || args(0) == "-h") {
-        Usage();
-        WScript.Quit(2);
-    }
 
+if (args.Count() == 3) {
     PROJECT_PATH=args(0);
-    if (args.Count() > 1) {
-        PACKAGE = args(1);
-    }
-    if (args.Count() > 2) {
-        ACTIVITY = args(2);
-    }
-}
-else {
-    Log("Error : No project path provided.");
-    Usage();
-    WScript.Quit(2);
+    PACKAGE=args(1);
+    ACTIVITY=args(2);
 }
 
 if(fso.FolderExists(PROJECT_PATH)) {
-    Log("Project already exists!", true);
-    WScript.Quit(2);
+    WScript.Echo("Project already exists!");
+    WScript.Quit(1);
 }
 
 var PACKAGE_AS_PATH=PACKAGE.replace(/\./g, '\\');
@@ -196,13 +162,13 @@ var TARGET=setTarget();
 var API_LEVEL=setApiLevel();
 var VERSION=read(ROOT+'\\VERSION').replace(/\r\n/,'').replace(/\n/,'');
 // create the project
-Log("Creating new android project...");
+WScript.Echo("Creating new android project...");
 exec('android.bat create project --target '+TARGET+' --path '+PROJECT_PATH+' --package '+PACKAGE+' --activity '+ACTIVITY);
 
 // build from source. distro should have these files
 if (!fso.FileExists(ROOT+'\\cordova-'+VERSION+'.jar') &&
     !fso.FileExists(ROOT+'\\cordova-'+VERSION+'.js')) {
-    Log("Building jar and js files...");
+    WScript.Echo("Building jar and js files...");
     // update the cordova framework project to a target that exists on this machine
     exec('android.bat update project --target '+TARGET+' --path '+ROOT+'\\framework');
     // pull down commons codec if necessary
@@ -211,14 +177,14 @@ if (!fso.FileExists(ROOT+'\\cordova-'+VERSION+'.jar') &&
 }
 
 // copy in the project template
-Log("Copying template files...");
+WScript.Echo("Copying template files...");
 exec('%comspec% /c xcopy "'+ ROOT + '"\\bin\\templates\\project\\res '+PROJECT_PATH+'\\res\\ /E /Y');
 exec('%comspec% /c xcopy "'+ ROOT + '"\\bin\\templates\\project\\assets '+PROJECT_PATH+'\\assets\\ /E /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\project\\AndroidManifest.xml ' + PROJECT_PATH + '\\AndroidManifest.xml /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\project\\Activity.java '+ ACTIVITY_PATH +' /Y');
 
 // check if we have the source or the distro files
-Log("Copying js, jar & config.xml files...");
+WScript.Echo("Copying js, jar & config.xml files...");
 if(fso.FolderExists(ROOT + '\\framework')) {
     exec('%comspec% /c copy "'+ROOT+'"\\framework\\assets\\www\\cordova-'+VERSION+'.js '+PROJECT_PATH+'\\assets\\www\\cordova-'+VERSION+'.js /Y');
     exec('%comspec% /c copy "'+ROOT+'"\\framework\\cordova-'+VERSION+'.jar '+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar /Y');
@@ -236,17 +202,10 @@ if(fso.FolderExists(ROOT + '\\framework')) {
 
 // copy cordova scripts
 fso.CreateFolder(PROJECT_PATH + '\\cordova');
-fso.CreateFolder(PROJECT_PATH + '\\cordova\\lib');
 createAppInfoJar();
-Log("Copying cordova command tools...");
+WScript.Echo("Copying cordova command tools...");
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\appinfo.jar ' + PROJECT_PATH + '\\cordova\\appinfo.jar /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\cordova.js ' + PROJECT_PATH + '\\cordova\\lib\\cordova.js /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\install-device.bat ' + PROJECT_PATH + '\\cordova\\lib\\install-device.bat /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\install-emulator.bat ' + PROJECT_PATH + '\\cordova\\lib\\install-emulator.bat /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\list-emulator-images.bat ' + PROJECT_PATH + '\\cordova\\lib\\list-emulator-images.bat /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\list-devices.bat ' + PROJECT_PATH + '\\cordova\\lib\\list-devices.bat /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\list-started-emulators.bat ' + PROJECT_PATH + '\\cordova\\lib\\list-started-emulators.bat /Y');
-exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\lib\\start-emulator.bat ' + PROJECT_PATH + '\\cordova\\lib\\start-emulator.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\cordova.js ' + PROJECT_PATH + '\\cordova\\cordova.js /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\cordova.bat ' + PROJECT_PATH + '\\cordova\\cordova.bat /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\clean.bat ' + PROJECT_PATH + '\\cordova\\clean.bat /Y');
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\build.bat ' + PROJECT_PATH + '\\cordova\\build.bat /Y');
@@ -254,7 +213,7 @@ exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\log.bat ' + PROJECT
 exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\run.bat ' + PROJECT_PATH + '\\cordova\\run.bat /Y');
 
 // interpolate the activity name and package
-Log("Updating AndroidManifest.xml and Main Activity...");
+WScript.Echo("Updating AndroidManifest.xml and Main Activity...");
 replaceInFile(ACTIVITY_PATH, /__ACTIVITY__/, ACTIVITY);
 replaceInFile(ACTIVITY_PATH, /__ID__/, PACKAGE);
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/build
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/build b/lib/cordova-android/bin/templates/cordova/build
index 3cbd9c1..e586e4d 100755
--- a/lib/cordova-android/bin/templates/cordova/build
+++ b/lib/cordova-android/bin/templates/cordova/build
@@ -1,4 +1,3 @@
-#!/bin/bash
 # 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
@@ -16,8 +15,10 @@
 # specific language governing permissions and limitations
 # under the License.
 
+#!/bin/bash
+
 set -e
 
 CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
 
-bash "$CORDOVA_PATH"/lib/cordova build "$@"
+bash "$CORDOVA_PATH"/cordova build

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/build.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/build.bat b/lib/cordova-android/bin/templates/cordova/build.bat
index 7aa7c75..8e6ca9a 100644
--- a/lib/cordova-android/bin/templates/cordova/build.bat
+++ b/lib/cordova-android/bin/templates/cordova/build.bat
@@ -1,2 +1,18 @@
-@ECHO OFF
-%~dp0\cordova.bat build %*
\ No newline at end of file
+:: 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.
+
+%~dp0\cordova.bat build

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/clean
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/clean b/lib/cordova-android/bin/templates/cordova/clean
index f52966a..53b7f9a 100755
--- a/lib/cordova-android/bin/templates/cordova/clean
+++ b/lib/cordova-android/bin/templates/cordova/clean
@@ -1,4 +1,3 @@
-#!/bin/bash
 # 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
@@ -16,8 +15,10 @@
 # specific language governing permissions and limitations
 # under the License.
 
+#!/bin/bash
+
 set -e
 
 CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd )
 
-bash "$CORDOVA_PATH"/lib/cordova clean "$@"
+bash "$CORDOVA_PATH"/cordova clean

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/clean.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/clean.bat b/lib/cordova-android/bin/templates/cordova/clean.bat
index b41bdc9..fe5c09f 100644
--- a/lib/cordova-android/bin/templates/cordova/clean.bat
+++ b/lib/cordova-android/bin/templates/cordova/clean.bat
@@ -1,2 +1,18 @@
-@ECHO OFF
-%~dp0\cordova.bat clean %*
+:: 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.
+
+%~dp0\cordova.bat clean

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/cordova
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/cordova b/lib/cordova-android/bin/templates/cordova/cordova
new file mode 100755
index 0000000..1945a4c
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/cordova
@@ -0,0 +1,159 @@
+# 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.
+
+#!/bin/bash
+
+
+PROJECT_PATH=$( cd "$( dirname "$0" )/.." && pwd )
+
+function check_devices {
+# FIXME
+    local devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep device`
+    if [ -z "$devices"  ] ; then
+        echo "1"
+    else
+        echo "0"
+    fi
+}
+
+function emulate {
+    declare -a avd_list=($(android list avd | grep "Name:" | cut -f 2 -d ":" | xargs))
+    # we need to start adb-server
+    adb start-server 1>/dev/null
+
+    # Do not launch an emulator if there is already one running or if a device is attached
+    if [ $(check_devices) == 0 ] ; then
+        return
+    fi
+
+    local avd_id="1000" #FIXME: hopefully user does not have 1000 AVDs
+    # User has no AVDs
+    if [ ${#avd_list[@]} == 0 ]
+    then
+        echo "You don't have any Android Virtual Devices. Please create at least one AVD."
+        echo "android"
+    fi
+    # User has only one AVD
+    if [ ${#avd_list[@]} == 1 ]
+    then
+        emulator -cpu-delay 0 -no-boot-anim -cache /tmp/cache -avd ${avd_list[0]} 1> /dev/null 2>&1 &
+    # User has more than 1 AVD
+    elif [ ${#avd_list[@]} -gt 1 ]
+    then
+        while [ -z ${avd_list[$avd_id]} ]
+        do
+            echo "Choose from one of the following Android Virtual Devices [0 to $((${#avd_list[@]}-1))]:"
+            for(( i = 0 ; i < ${#avd_list[@]} ; i++ ))
+            do
+                echo "$i) ${avd_list[$i]}"
+            done
+            read -t 5 -p "> " avd_id
+            # default value if input timeout
+            if [ $avd_id -eq 1000 ] ; then avd_id=0 ; fi
+        done
+        emulator -cpu-delay 0 -no-boot-anim -cache /tmp/cache -avd ${avd_list[$avd_id]} 1> /dev/null 2>&1 &
+    fi
+    
+}
+
+function clean {
+    ant clean
+}
+# has to be used independently and not in conjunction with other commands
+function log {
+    adb logcat
+}
+
+function run {
+    clean && emulate && wait_for_device && install && launch 
+}
+
+function install {
+    
+    declare -a devices=($(adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep device | cut -f 1))
+    local device_id="1000" #FIXME: hopefully user does not have 1000 AVDs
+    
+    if [ ${#devices[@]} == 0 ]
+    then
+        # should not reach here. Emulator should launch or device should be attached
+        echo "Emulator not running or device not attached. Could not install debug package"
+        exit 70
+    fi
+    
+    if [ ${#devices[@]} == 1 ]
+    then
+        export ANDROID_SERIAL=${devices[0]}
+    # User has more than 1 AVD
+    elif [ ${#devices[@]} -gt 1 ]
+    then
+        while [ -z ${devices[$device_id]} ]
+        do
+            echo "Choose from one of the following devices/emulators [0 to $((${#devices[@]}-1))]:"
+            for(( i = 0 ; i < ${#devices[@]} ; i++ ))
+            do
+                echo "$i) ${devices[$i]}"
+            done
+            read -t 5 -p "> " device_id
+            # default value if input timeout
+            if [ $device_id -eq 1000 ] ; then device_id=0 ; fi
+        done
+        export ANDROID_SERIAL=${devices[$device_id]}
+    fi
+
+    ant debug install
+}
+
+function build {
+    ant debug
+}
+
+function release {
+    ant release
+}
+
+function wait_for_device {
+    local i="0"
+    echo -n "Waiting for device..."
+
+    while [ $i -lt 300 ]
+    do
+        if [ $(check_devices) -eq 0 ]
+        then
+            break
+        else
+            sleep 1
+            i=$[i+1]
+            echo -n "."
+        fi
+    done
+    # Device timeout: emulator has not started in time or device not attached
+    if [ $i -eq 300 ]
+    then
+        echo "device timeout!"
+        exit 69
+    else
+        echo "connected!"
+    fi
+}
+
+function launch {
+    local launch_str=$(java -jar "$PROJECT_PATH"/cordova/appinfo.jar "$PROJECT_PATH"/AndroidManifest.xml)
+    adb shell am start -n $launch_str 
+}
+
+# TODO parse arguments
+(cd "$PROJECT_PATH" && $1)

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/cordova.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/cordova.bat b/lib/cordova-android/bin/templates/cordova/cordova.bat
index 9b56199..22c289a 100644
--- a/lib/cordova-android/bin/templates/cordova/cordova.bat
+++ b/lib/cordova-android/bin/templates/cordova/cordova.bat
@@ -1,5 +1,3 @@
-@ECHO OFF
-GOTO BEGIN
 :: 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
@@ -16,13 +14,14 @@ GOTO BEGIN
 :: KIND, either express or implied.  See the License for the
 :: specific language governing permissions and limitations
 :: under the License.
-:BEGIN
+
+@ECHO OFF
 IF NOT DEFINED JAVA_HOME GOTO MISSING
 FOR %%X in (java.exe ant.bat android.bat) do (
     SET FOUND=%%~$PATH:X
     IF NOT DEFINED FOUND GOTO MISSING
 )
-cscript %~dp0\lib\cordova.js %* //nologo
+cscript %~dp0\cordova.js %*
 GOTO END
 :MISSING
 ECHO Missing one of the following:

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/cordova.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/cordova.js b/lib/cordova-android/bin/templates/cordova/cordova.js
new file mode 100644
index 0000000..51533cb
--- /dev/null
+++ b/lib/cordova-android/bin/templates/cordova/cordova.js
@@ -0,0 +1,137 @@
+// 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 ROOT = WScript.ScriptFullName.split('\\cordova\\cordova.js').join(''),
+    shell=WScript.CreateObject("WScript.Shell");
+
+function exec(command) {
+    var oExec=shell.Exec(command);
+    var output = new String();
+    while(oExec.Status == 0) {
+        if(!oExec.StdOut.AtEndOfStream) {
+            var line = oExec.StdOut.ReadLine();
+            // XXX: Change to verbose mode 
+            // WScript.StdOut.WriteLine(line);
+            output += line;
+        }
+        WScript.sleep(100);
+    }
+
+    return output;
+}
+
+function device_running() {
+    var local_devices = shell.Exec("%comspec% /c adb devices").StdOut.ReadAll();
+    if(local_devices.match(/\w+\tdevice/)) {
+        WScript.Echo("Yes");
+        return true;
+    }
+    WScript.Echo("No");
+    return false;
+}
+function emulate() {
+    // don't run emulator if a device is plugged in or if emulator is already running
+    if(device_running()) {
+        //WScript.Echo("Device or Emulator already running!");
+        return;
+    }
+    var oExec = shell.Exec("%comspec% /c android.bat list avd");
+    var avd_list = [];
+    var avd_id = -10;
+    while(!oExec.StdOut.AtEndOfStream) {
+        var output = oExec.StdOut.ReadLine();
+        if(output.match(/Name: (.)*/)) {
+            avd_list.push(output.replace(/ *Name:\s/, ""));
+        }
+    }
+    // user has no AVDs
+    if(avd_list.length == 0) {
+        WScript.Echo("You don't have any Android Virtual Devices. Please create at least one AVD.");
+        WScript.Echo("android");
+        WScript.Quit(1);
+    }
+    // user has only one AVD so we launch that one
+    if(avd_list.length == 1) {
+
+        shell.Run("emulator -cpu-delay 0 -no-boot-anim -cache %Temp%\cache -avd "+avd_list[0]);
+    }
+
+    // user has more than one avd so we ask them to choose
+    if(avd_list.length > 1) {
+        while(!avd_list[avd_id]) {
+            WScript.Echo("Choose from one of the following Android Virtual Devices [0 to "+(avd_list.length - 1)+"]:")
+            for(i = 0, j = avd_list.length ; i < j ; i++) {
+                WScript.Echo((i)+") "+avd_list[i]);
+            }
+            WScript.StdOut.Write("> ");
+            avd_id = new Number(WScript.StdIn.ReadLine());
+        }
+
+        shell.Run("emulator -cpu-delay 0 -no-boot-anim -cache %Temp%\\cache -avd "+avd_list[avd_id], 0, false);
+    }
+}
+
+function clean() {
+    WScript.Echo("Cleaning project...");
+    exec("%comspec% /c ant.bat clean -f "+ROOT+"\\build.xml 2>&1");
+}
+
+function build() {
+    WScript.Echo("Building project...");
+    exec("%comspec% /c ant.bat debug -f "+ROOT+"\\build.xml 2>&1");
+}
+
+function install() {
+    WScript.Echo("Building/Installing project...");
+    exec("%comspec% /c ant.bat debug install -f "+ROOT+"\\build.xml 2>&1");
+}
+
+function log() {
+    shell.Run("%comspec% /c adb logcat");
+}
+
+function launch() {
+    WScript.Echo("Launching app...");
+    var launch_str=exec("%comspec% /c java -jar "+ROOT+"\\cordova\\appinfo.jar "+ROOT+"\\AndroidManifest.xml");
+    //WScript.Echo(launch_str);
+    exec("%comspec% /c adb shell am start -n "+launch_str+" 2>&1");
+}
+
+function run() {
+    var i=0;
+   clean();
+   emulate();
+   WScript.Stdout.Write('Waiting for device...');
+   while(!device_running() && i < 300) {
+        WScript.Stdout.Write('.');
+        WScript.sleep(1000);
+        i += 1;
+   }
+   if(i == 300) {
+       WScript.Stderr.WriteLine("device/emulator timeout!"); 
+   } else {
+       WScript.Stdout.WriteLine("connected!");
+   }
+   install();
+   launch();
+}
+var args = WScript.Arguments;
+if(args.count() != 1) {
+    WScript.StdErr.Write("An error has occured!\n");
+    WScript.Quit(1);
+}
+eval(args(0)+"()");

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/lib/cordova
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/cordova b/lib/cordova-android/bin/templates/cordova/lib/cordova
deleted file mode 100755
index 294df49..0000000
--- a/lib/cordova-android/bin/templates/cordova/lib/cordova
+++ /dev/null
@@ -1,386 +0,0 @@
-#!/bin/bash
-#   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.
-
-PROJECT_PATH=$( cd "$( dirname "$0" )/../.." && pwd )
-
-function list_devices {
-    IFS=$'\n'
-    devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep -v 'emulator'`
-    device_list=($devices)
-    if [[ ${#device_list[@]} > 0 ]] ; then
-        for i in ${devices[@]}
-        do
-            # remove space and 'device'
-            echo ${i/[^a-zA-Z0-9._]device/}
-        done
-    else
-        echo "No devices found."
-        exit 2
-    fi
-}
-
-function list_started_emulators {
-    IFS=$'\n'
-    devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep 'emulator'`
-    emulator_list=($devices)
-    if [[ ${#emulator_list[@]} > 0 ]] ; then
-        for i in ${emulator_list[@]}
-        do
-            # remove space and 'device'
-            echo ${i/[^a-zA-Z0-9._]device/}
-        done
-    else
-        echo "No started emulators found, you can start an emulator by using the command"
-        echo " 'cordova/lib/start-emulator'"
-        exit 2
-    fi
-}
-
-function list_emulator_images {
-    emulator_images=`android list avds | grep "Name:" | cut -f 2 -d ":"`
-    emulator_list=($emulator_images)
-    if [[ ${#emulator_list[@]} > 0 ]] ; then
-        for i in ${emulator_list[@]}
-        do
-            echo ${i/[^a-zA-Z0-9._]/}
-        done
-    else
-        echo "No emulators found, if you would like to create an emulator follow the instructions"
-        echo " provided here : http://developer.android.com/tools/devices/index.html"
-        echo " Or run 'android create avd --name <name> --target <targetID>' in on the command line."
-        exit 2
-    fi
-}
-
-function start_emulator {
-    emulator_images=`android list avds | grep "Name:" | cut -f 2 -d ":"`
-    # if target emulator is provided
-    if [[ "$#" -eq 1 ]] ; then
-        # check that it exists
-        if [[ $emulator_images =~ $1 ]] ; then
-            #xterm -e emulator -avd $1 &
-            emulator -avd $1 1> /dev/null 2>&1 &
-        else
-            echo "Could not find the provided emulator, make sure the emulator exists"
-            echo " by checking 'cordova/lib/list-emulator-images'"
-            exit 2
-        fi
-    else
-        # start first emulator
-        emulator_list=($emulator_images)
-        if [[ ${#emulator_list[@]} > 0 ]] ; then
-            #xterm -e emulator -avd ${emulator_list[0]} &
-            emulator -avd ${emulator_list[0]/[^a-zA-Z0-9._]/} 1> /dev/null 2>&1 &
-        else
-            echo "No emulators found, if you would like to create an emulator follow the instructions"
-            echo " provided here : http://developer.android.com/tools/devices/index.html"
-            echo " Or run 'android create avd --name <name> --target <targetID>' in on the command line."
-            exit 2
-        fi
-    fi
-}
-
-function install_device {
-    IFS=$'\n'
-    devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep -v 'emulator'`
-    device_list=($devices)
-    if [[ ${#device_list[@]} > 0 ]] ; then
-        apks=`find $PROJECT_PATH/bin -type f -maxdepth 1 | egrep '\.apk$'`
-        apk_list=($apks)
-        if [[ ${#apk_list[@]} > 0 ]] ; then
-            local target
-            # handle target emulator
-            if [[ "$#" -eq 1 ]] ; then
-                # deploy to given target
-                target=${1/--target=/}
-            else
-                # delete trailing space and 'device' after device ID
-                target=${device_list[0]/[^a-zA-Z0-9._]device/}
-            fi
-            echo "Installing ${apk_list[0]} onto device $target..."
-            adb -s $target install -r ${apk_list[0]};
-            echo "Launching application..."
-            local launch_str=$(java -jar "$PROJECT_PATH"/cordova/appinfo.jar "$PROJECT_PATH"/AndroidManifest.xml)
-            adb -s $target shell am start -W -a android.intent.action.MAIN -n $launch_str
-        else
-            echo "Application package not found, could not install to device"
-            echo " make sure your application is built before deploying."
-            exit 2
-        fi
-    else
-        echo "No devices found to deploy to. Please make sure your device is connected"
-        echo " and you can view it using the 'cordova/lib/list-devices' command."
-        exit 2
-    fi
-}
-
-function install_emulator {
-    IFS=$'\n'
-    # check that there is an emulator to deploy to
-    emulator_string=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'emulator'`
-    emulator_list=($emulator_string)
-    if [[ ${#emulator_list[@]} > 0 ]] ; then
-        apks=`find $PROJECT_PATH/bin -type f -maxdepth 1 | egrep '\.apk$'`
-        apk_list=($apks)
-        if [[ ${#apk_list[@]} > 0 ]] ; then
-            local target
-            # handle target emulator
-            if [[ "$#" -eq 1 ]] ; then
-                # deploy to given target
-                target=${1/--target=/}
-            else
-                # delete trailing space and 'device' after emulator ID
-                target=${emulator_list[0]/[^a-zA-Z0-9._]device/}
-            fi
-            echo "Installing ${apk_list[0]} onto $target..."
-            adb -s $target install -r ${apk_list[0]};
-            echo "Launching application..."
-            local launch_str=$(java -jar "$PROJECT_PATH"/cordova/appinfo.jar "$PROJECT_PATH"/AndroidManifest.xml)
-            adb -s $target shell am start -W -a android.intent.action.MAIN -n $launch_str
-
-        else
-            echo "Application package not found, could not install to device"
-            echo " make sure your application is built before deploying."
-            exit 2
-        fi
-    else
-        echo "No emulators found to deploy to. Please make sure your emulator is started"
-        echo " and you can view it using the 'cordova/lib/list-started-emulators' command."
-        exit 2
-    fi
-}
-
-# cleans the project
-function clean {
-    echo "Cleaning project..."
-    ant clean
-}
-
-# has to be used independently and not in conjunction with other commands
-function log {
-    # filter out nativeGetEnabledTags spam from latest sdk bug.
-    adb logcat | grep -v nativeGetEnabledTags
-}
-
-
-function build {
-    if [[ "$#" -eq 1 ]] ; then
-        if [[ $1 == "--debug" ]] ; then
-            clean
-            ant debug -f "$PROJECT_PATH"/build.xml
-        elif [[ $1 == "--release" ]] ; then
-            clean
-            ant release -f "$PROJECT_PATH"/build.xml
-        elif [[ $1 == "--nobuild" ]] ; then
-            echo "Skipping build..."
-        else
-            echo "Error : Build command '$1' not recognized."
-            exit 2
-        fi
-    else
-        echo "Warning : [ --debug | --release | --nobuild ] not specified, defaulting to --debug"
-        clean
-        ant debug -f "$PROJECT_PATH"/build.xml
-    fi
-}
-
-
-function wait_for_emulator {
-    emulator_string=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep 'emulator'`
-    old_started=($emulator_string)
-    local new_started
-    local new_emulator_name
-    local i="0"
-    echo -n "Waiting for emulator..."
-    while [ $i -lt 300 ]
-    do
-        emulator_string=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep 'emulator'`
-        new_started=($emulator_string)
-        if [[ ${#new_started[@]} > ${#old_started[@]} && -z "$new_emulator_name" ]] ; then
-            # get the name of the started emulator
-            local count="0"
-            if [[ ${#old_started[@]} == 0 ]] ; then
-                new_emulator_name=${new_started[$count]/[^a-zA-Z0-9._]device/}
-            else
-                for count in {0...${#old_started[@]}}
-                do
-                    if [[ ! ${new_started[$count]} == ${old_started[$count]} ]] ; then
-                        new_emulator_name=${new_started[$count]/[^a-zA-Z0-9._]device/}
-                    fi
-                done
-                if [[ -z "$new_emulator_name" ]] ; then
-                    count=$[count+1]
-                    new_emulator_name=${new_started[$count]/[^a-zA-Z0-9._]device/}
-                fi
-            fi
-        elif [[ "$new_emulator_name" ]] ; then
-            boot_anim=`adb -s $new_emulator_name shell getprop init.svc.bootanim`
-            if [[ $boot_anim =~ "stopped" ]] ; then
-                break
-            else
-                sleep 1
-                i=$[i+1]
-                echo -n "."
-            fi
-        else
-            sleep 1
-            i=$[i+1]
-            echo -n "."
-        fi
-    done
-    # Device timeout: emulator has not started in time
-    if [ $i -eq 300 ]
-    then
-        echo "emulator timeout!"
-        exit 69
-    else
-        echo "connected!"
-    fi
-}
-
-function run {
-    IFS=$'\n'
-    if [[ "$#" -eq 2 ]] ; then
-        build $2
-        if [[ $1 == "--device" ]] ; then
-            install_device
-        elif [[ $1 == "--emulator" ]] ; then
-            install_emulator
-        elif [[ $1 =~ "--target=" ]]; then
-            install_device $1
-        else
-            echo "Error : '$1' is not recognized as an install option"
-        fi
-    elif [[ "$#" -eq 1 ]] ; then
-        if [[ $1 == "--debug" || $1 == "--release" || $1 == "--nobuild" ]] ; then
-            build $1
-        elif [[ $1 == "--device" ]] ; then
-            install_device
-        elif [[ $1 == "--emulator" ]] ; then
-            install_emulator
-        elif [[ $1 =~ "--target=" ]]; then
-            install_device $1
-        else
-            echo "Error : '$1' is not recognized as an install option"
-        fi
-    else
-        echo "Warning : [ --device | --emulate | --target=<targetID> ] not specified, using defaults."
-        build
-        devices=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep -v 'emulator'`
-        device_list=($devices)
-        emulator_string=`adb devices | awk '/List of devices attached/ { while(getline > 0) { print }}' | grep 'device' | grep 'emulator'`
-        emulator_list=($emulator_string)
-        if [[ ${#device_list[@]} > 0 ]] ; then
-            install_device
-        elif [[ ${#emulator_list[@]} > 0 ]] ; then
-            install_emulator
-        else
-            emulator_images=`android list avds | grep "Name:" | cut -f 2 -d ":"`
-            echo $emulator_images
-            emulator_image_list=($emulator_images)
-            if [[ ${#emulator_image_list[@]} > 0 ]] ; then
-                echo "Starting emulator : ${emulator_image_list[0]}" 
-                emulator -avd ${emulator_image_list[0]/[^.\w]/} 1> /dev/null 2>&1 &
-                wait_for_emulator
-                install_emulator
-            else
-                # TODO : look for emulator images and start one if it's availible
-                echo "Error : there are no availible devices or emulators to deploy to."
-                echo " create an emulator or connect your device to run this command."
-                echo "If you would like to create an emulator follow the instructions"
-                echo " provided here : http://developer.android.com/tools/devices/index.html"
-                echo " Or run 'android create avd --name <name> --target <targetID>' in on the command line."
-                exit 2
-            fi
-        fi
-    fi
-}
-
-# parse command line arguments
-
-if [[ $# > 3 ]] ; then 
-    echo "Error :  too many arguments."
-    exit 2
-elif [[ $# == 3 ]] ; then
-    if [[ $1 == "run" ]] ; then
-        run $2 $3
-    else
-        echo "Error : too many arguments for '$1'"
-        exit 2
-    fi
-elif [[ $# == 2 ]] ; then
-    if [[ $1 == "run" ]] ; then
-        if [[ $2 == "--emulator" || $2 == "--device" || $2 =~ "--target=" ]] ; then
-            run $2 ''
-        elif [[ $2 == "--debug" || $2 == "--release" || $2 == "--nobuild" ]] ; then
-            run '' $2
-        else 
-            echo "Error : '$2' is not recognized as a run option."
-            exit 2
-        fi
-    elif [[ $1 == "build" ]] ; then
-        build $2
-    elif [[ $1 == "start-emulator" ]] ; then
-        start_emulator $2
-    elif [[ $1 == "install-device" ]] ; then
-        if [[ $2 =~ "--target=" ]] ; then
-            install_device $2
-        else
-            echo "Error : '$2' is not recognized as an install option"
-            exit 2
-        fi
-    elif [[ $1 == "install-emulator" ]] ; then
-        if [[ $2 =~ "--target=" ]] ; then
-            install_emulator $2
-        else
-            echo "Error : '$2' is not recognized as an install option"
-            exit 2
-        fi
-    else
-        echo "Error : '$1' is not recognized as an option that takes arguments"
-        exit 2
-    fi
-elif [[ $# == 1 ]] ; then
-    if [[ $1 == "run" ]] ; then
-        run
-    elif [[ $1 == "build" ]]; then
-        build
-    elif [[ $1 == "clean" ]]; then
-        clean
-    elif [[ $1 == "log" ]]; then
-        log
-    elif [[ $1 == "list-devices" ]]; then
-        list_devices
-    elif [[ $1 == "list-emulator-images" ]]; then
-        list_emulator_images
-    elif [[ $1 == "list-started-emulators" ]]; then
-        list_started_emulators
-    elif [[ $1 == "install-device" ]]; then
-        install_device
-    elif [[ $1 == "install-emulator" ]]; then
-        install_emulator
-    elif [[ $1 == "start-emulator" ]]; then
-        start_emulator
-    else
-        echo "Error : '$1' is not recognized as a tooling command."
-        exit 2
-    fi
-else
-    echo "Error : No command recieved, exiting..."
-    exit 2
-fi
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/lib/cordova.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/cordova.js b/lib/cordova-android/bin/templates/cordova/lib/cordova.js
deleted file mode 100644
index 28f9b3e..0000000
--- a/lib/cordova-android/bin/templates/cordova/lib/cordova.js
+++ /dev/null
@@ -1,593 +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 ROOT  = WScript.ScriptFullName.split('\\cordova\\lib\\cordova.js').join(''),
-    shell = WScript.CreateObject("WScript.Shell"),
-    fso   = WScript.CreateObject('Scripting.FileSystemObject');
-
-
-// log to stdout or stderr
-function Log(msg, error) {
-    if (error) {
-        WScript.StdErr.WriteLine(msg);
-    }
-    else {
-        WScript.StdOut.WriteLine(msg);
-    }
-} 
-
-// executes a commmand in the shell, returning stdout
-function exec(command) {
-    var oExec=shell.Exec(command);
-    var output = new String();
-    while (oExec.Status == 0) {
-        if (!oExec.StdOut.AtEndOfStream) {
-            var line = oExec.StdOut.ReadLine();
-            output += line;
-        }
-        WScript.sleep(100);
-    }
-    return output;
-}
-
-// executes a command in the shell, returns stdout or stderr if error
-function exec_out(command) {
-    var oExec=shell.Exec(command);
-    var output = new String();
-    while (oExec.Status == 0) {
-        if (!oExec.StdOut.AtEndOfStream) {
-            var line = oExec.StdOut.ReadLine();
-            // XXX: Change to verbose mode 
-            // WScript.StdOut.WriteLine(line);
-            output += line;
-        }
-        WScript.sleep(100);
-    }
-    //Check to make sure our scripts did not encounter an error
-    if (!oExec.StdErr.AtEndOfStream) {
-        var line = oExec.StdErr.ReadAll();
-        return {'error' : true, 'output' : line};
-    }
-    return {'error' : false, 'output' : output};
-}
-
-// executes a commmand in the shell and outputs stdout and fails on stderr
-function exec_verbose(command) {
-    //Log("Command: " + command);
-    var oShell=shell.Exec(command);
-    while (oShell.Status == 0) {
-        //Wait a little bit so we're not super looping
-        WScript.sleep(100);
-        //Print any stdout output from the script
-        if (!oShell.StdOut.AtEndOfStream) {
-            var line = oShell.StdOut.ReadLine();
-            Log(line);
-        }
-    }
-    //Check to make sure our scripts did not encounter an error
-    if (!oShell.StdErr.AtEndOfStream) {
-        var line = oShell.StdErr.ReadAll();
-        Log(line, true);
-        WScript.Quit(2);
-    }
-}
-
-function get_devices() {
-    var device_list = []
-    var local_devices = shell.Exec("%comspec% /c adb devices").StdOut.ReadAll();
-    if (local_devices.match(/\w+\tdevice/)) {
-        devices = local_devices.split('\r\n');
-        //format (ID DESCRIPTION)
-        for (i in devices) {
-            if (devices[i].match(/\w+\tdevice/) && !devices[i].match(/emulator/)) {
-                device_list.push(devices[i].replace(/\t/, ' '));
-            }
-        }
-    }
-    return device_list
-}
-
-function list_devices() {
-    var devices = get_devices();
-    if (devices.length > 0) {
-        for (i in devices) {
-            Log(devices[i]);
-        }
-    }
-    else {
-        Log('No devices found, if your device is connected and not showing,');
-        Log(' then try and install the drivers for your device.');
-        Log(' http://developer.android.com/tools/extras/oem-usb.html');
-    }
-
-}
-
-function get_emulator_images() {
-    // discription contains all data recieved squashed onto one line
-    var add_description = true;
-    var avd_list = [];
-    var local_emulators = shell.Exec("%comspec% /c android list avds").StdOut.ReadAll();
-    if (local_emulators.match(/Name\:/)) {
-        emulators = local_emulators.split('\n');
-        //format (ID DESCRIPTION)
-        var count = 0;
-        var output = '';
-        for (i in emulators) {
-            if (emulators[i].match(/Name\:/)) {
-                var emulator_name = emulators[i].replace(/\s*Name\:\s/, '') + ' ';
-                if (add_description) {
-                    count = 1;
-                    output += emulator_name
-                }
-                else {
-                    avd_list.push(emulator_name);
-                }
-            }
-            // add description if indicated (all data squeezed onto one line)
-            if (count > 0) {
-                var emulator_description = emulators[i].replace(/\s*/g, '');
-                if (count > 4) {
-                    avd_list.push(output + emulator_description);
-                    count = 0;
-                    output = '';
-                }
-                else {
-                    count++;
-                    output += emulator_description + ' '
-                }
-            }
-        }
-    }
-    return avd_list;
-}
-
-function list_emulator_images() {
-    var images = get_emulator_images();
-    if (images.length > 0) {
-        for(i in images) {
-            Log(images[i]);
-        }
-    }
-    else {
-        Log('No emulators found, if you would like to create an emulator follow the instructions');
-        Log(' provided here : http://developer.android.com/tools/devices/index.html');
-        Log(' Or run \'android create avd --name <name> --target <targetID>\' in on the command line.');
-    }
-}
-
-function get_started_emulators() {
-    var started_emulators = [];
-    var local_devices = shell.Exec("%comspec% /c adb devices").StdOut.ReadAll();
-    if (local_devices.match(/emulator/)) {
-        devices = local_devices.split('\r\n');
-        //format (ID DESCRIPTION)
-        for (i in devices) {
-            if (devices[i].match(/\w+\tdevice/) && devices[i].match(/emulator/)) {
-                started_emulators.push(devices[i].replace(/\t/, ' '));
-            }
-        }
-    }
-    return started_emulators
-}
-
-function list_started_emulators() {
-    var images = get_started_emulators();
-    if (images.length > 0) {
-        for(i in images) {
-            Log(images[i]);
-        }
-    }
-    else {
-        Log('No started emulators found, if you would like to start an emulator call \'list-emulator-images\'');
-        Log(' to get the name of an emulator and then start the emulator with \'start-emulator <Name>\'');
-    }
-}
-
-function start_emulator(name) {  
-    var emulators = get_emulator_images();
-    var started_emulators = get_started_emulators();
-    var num_started = started_emulators.length;
-    var emulator_name;
-    var started = false;
-    if (name) {
-        for (i in emulators) {
-            if (emulators[i].substr(0,name.length) == name) {
-                Log("Starting emulator : " + name);
-                shell.Run("%comspec% /c start cmd /c emulator -avd " + name);
-                //shell.Run("%comspec% /c start cmd /c emulator -cpu-delay 0 -no-boot-anim -cache %Temp%\cache -avd " + name);
-                started = true;
-            }
-        }
-    }
-    else {
-        if (emulators.length > 0 && started_emulators < 1) {
-            emulator_name = emulators[0].split(' ', 1)[0];
-            start_emulator(emulator_name);
-            return;
-        } else if (started_emulators.length > 0) {
-            Log("Emulator already started : " + started_emulators[0].split(' ', 1));
-            return;
-        } else {
-            Log("Error : unable to start emulator, ensure you have emulators availible by checking \'list-emulator-images\'", true);
-            WScript.Quit(2);
-        }
-    }
-    if (!started) {
-        Log("Error : unable to start emulator, ensure you have emulators availible by checking \'list-emulator-images\'", true);
-        WScript.Quit(2);
-    }
-    else { // wait for emulator to boot before returning
-        WScript.Stdout.Write('Booting up emulator..');
-        var boot_anim = null;
-        var emulator_ID = null;
-        var new_started = get_started_emulators();
-        var i = 0;
-        // use boot animation property to tell when boot is complete.
-        while ((boot_anim == null || !boot_anim.output.match(/stopped/)) && i < 100) {
-            if (new_started.length > started_emulators.length && emulator_ID == null) {
-                // find new emulator that was just started to get it's ID
-                for(var i = 0; i < new_started.length; i++) {
-                    if (new_started[i] != started_emulators[i]) {
-                        emulator_ID = new_started[i].split(' ', 1)[0];
-                        boot_anim = exec_out('%comspec% /c adb -s ' + emulator_ID + ' shell getprop init.svc.bootanim');
-                        break;
-                    }
-                }
-            }
-            else if (boot_anim == null) {
-                new_started = get_started_emulators(); 
-            }
-            else {
-                boot_anim = exec_out('%comspec% /c adb -s ' + emulator_ID + ' shell getprop init.svc.bootanim'); 
-            }
-            i++;
-            WScript.Stdout.Write('.');
-            WScript.Sleep(2000);
-        }
-        if (i < 100) {
-            Log('\nBoot Complete!');
-        } else {
-             Log('\nEmulator boot timed out. Failed to load emulator');
-             WScript.Quit(2);
-        }
-    }
-}
-
-function install_device(target) {
-    var devices = get_devices();
-    var use_target = false;
-    if (devices.length < 1) {
-        Log("Error : No devices found to install to, make sure there are devices", true);
-        Log(" availible by checking \'<project_dir>\\cordova\\lib\\list-devices\'", true);
-        WScript.Quit(2);
-    }
-    if (target) {
-        var exists = false;
-        for (i in devices) {
-            if (devices[i].substr(0,target.length) == target)
-            {
-                exists = true;
-                break;
-            }
-        }
-        if (!exists) {
-            Log("Error : Unable to find target " + target, true);
-            Log("Please ensure the target exists by checking \'<project>\\cordova\\lib\\list-devices'");
-            WScript.Quit(2);
-        }
-        use_target = true;
-    }
-    // check if file .apk has been created
-    if (fso.FolderExists(ROOT + '\\bin')) {
-        var path_to_apk;
-        var out_folder = fso.GetFolder(ROOT + '\\bin');
-        var out_files = new Enumerator(out_folder.Files);
-        for (;!out_files.atEnd(); out_files.moveNext()) {
-            var path = out_files.item() + '';
-            if (fso.GetExtensionName(path) == 'apk' && !path.match(/unaligned/)) {
-                path_to_apk = out_files.item();
-                break;
-            }
-        }
-        if (path_to_apk) {
-            var launch_name = exec_out("%comspec% /c java -jar "+ROOT+"\\cordova\\appinfo.jar "+ROOT+"\\AndroidManifest.xml");
-            if (launch_name.error) {
-                Log("Failed to get application name from appinfo.jar + AndroidManifest : ", true);
-                Log("Output : " + launch_name.output, true);
-                WScript.Quit(2);
-            }
-            // install on device (-d)
-            Log("Installing app on device...");
-            var cmd;
-            if (use_target) {
-                cmd = '%comspec% /c adb -s ' + target + ' install -r ' + path_to_apk;
-            } else {
-                cmd = '%comspec% /c adb -s ' + devices[0].split(' ', 1)[0] + ' install -r ' + path_to_apk;
-            }
-            var install = exec_out(cmd);
-            if ( install.error && install.output.match(/Failure/)) {
-                Log("Error : Could not install apk to device : ", true);
-                Log(install.output, true);
-                WScript.Quit(2);
-            }
-            else {
-                Log(install.output);
-            }
-            // run on device
-            Log("Launching application...");
-            cmd;
-            if (use_target) {
-                cmd = '%comspec% /c adb -s ' + target + ' shell am start -W -a android.intent.action.MAIN -n ' + launch_name.output;
-            } else {
-                cmd = '%comspec% /c adb -s ' + devices[0].split(' ', 1)[0] + ' shell am start -W -a android.intent.action.MAIN -n ' + launch_name.output;
-            }
-            exec_verbose(cmd);
-        }
-        else {
-            Log('Failed to find apk, make sure you project is built and there is an ', true);
-            Log(' apk in <project>\\bin\\.  To build your project use \'<project>\\cordova\\build\'', true);
-            WScript.Quit(2);
-        }
-    }
-}
-
-function install_emulator(target) {
-    var emulators = get_started_emulators();
-    var use_target = false;
-    if (emulators.length < 1) {
-        Log("Error : No emulators found to install to, make sure there are emulators", true);
-        Log(" availible by checking \'<project_dir>\\cordova\\lib\\list-started-emulators\'", true);
-        WScript.Quit(2);
-    }
-    if (target) {
-        var exists = false;
-        for (i in emulators) {
-            if (emulators[i].substr(0,target.length) == target)
-            {
-                exists = true;
-                break;
-            }
-        }
-        if (!exists) {
-            Log("Error : Unable to find target " + target, true);
-            Log("Please ensure the target exists by checking \'<project>\\cordova\\lib\\list-started-emulators'")
-        }
-        use_target = true;
-    } else {
-        target = emulators[0].split(' ', 1)[0];
-        Log("Deploying to emulator : " + target);
-    }
-    // check if file .apk has been created
-    if (fso.FolderExists(ROOT + '\\bin')) {
-        var path_to_apk;
-        var out_folder = fso.GetFolder(ROOT + '\\bin');
-        var out_files = new Enumerator(out_folder.Files);
-        for (;!out_files.atEnd(); out_files.moveNext()) {
-            var path = out_files.item() + '';
-            if (fso.GetExtensionName(path) == 'apk' && !path.match(/unaligned/)) {
-                path_to_apk = out_files.item();
-                break;
-            }
-        }
-        if (path_to_apk) {
-            var launch_name = exec_out("%comspec% /c java -jar "+ROOT+"\\cordova\\appinfo.jar "+ROOT+"\\AndroidManifest.xml");
-            if (launch_name.error) {
-                Log("Failed to get application name from appinfo.jar + AndroidManifest : ", true);
-                Log("Output : " + launch_name.output, true);
-                WScript.Quit(2);
-            }
-            // install on emulator (-e)
-            Log("Installing app on emulator...");
-            var cmd = '%comspec% /c adb -s ' + target + ' install -r ' + path_to_apk;
-            var install = exec_out(cmd);
-            if ( install.error && install.output.match(/Failure/)) {
-                Log("Error : Could not install apk to emulator : ", true);
-                Log(install.output, true);
-                WScript.Quit(2);
-            }
-            else {
-                Log(install.output);
-            }
-            // run on emulator
-            Log("Launching application...");
-            cmd;
-            if (use_target) {
-                cmd = '%comspec% /c adb -s ' + target + ' shell am start -W -a android.intent.action.MAIN -n ' + launch_name.output;
-            } else {
-                cmd = '%comspec% /c adb -s ' + emulators[0].split(' ', 1)[0] + ' shell am start -W -a android.intent.action.MAIN -n ' + launch_name.output
-            }
-            exec_verbose(cmd);
-        }
-        else {
-            Log('Failed to find apk, make sure you project is built and there is an ', true);
-            Log(' apk in <project>\\bin\\.  To build your project use \'<project>\\cordova\\build\'', true);
-            WScript.Quit(2);
-        }
-    }
-    else {
-        Log('Failed to find apk, make sure you project is built and there is an ', true);
-        Log(' apk in <project>\\bin\\.  To build your project use \'<project>\\cordova\\build\'', true);
-        WScript.Quit(2);
-    }
-}
-
-function clean() {
-    Log("Cleaning project...");
-    exec("%comspec% /c ant.bat clean -f "+ROOT+"\\build.xml 2>&1");
-}
-
-function build(build_type) {
-    if (build_type) {
-        switch (build_type) {
-            case "--debug" :
-                clean();
-                Log("Building project...");
-                exec_verbose("%comspec% /c ant.bat debug -f "+ROOT+"\\build.xml 2>&1");
-                break;
-            case "--release" :
-                clean();
-                Log("Building project...");
-                exec_verbose("%comspec% /c ant.bat release -f "+ROOT+"\\build.xml 2>&1");
-                break;
-            case "--nobuild" :
-                Log("Skipping build process.");
-                break;
-            default :
-                Log("Build option not recognized: " + build_type, true);
-                WScript.Quit(2);
-                break;
-        }
-    }
-    else {
-        Log("WARNING: [ --debug | --release | --nobuild ] not specified, defaulting to --debug.");
-        exec_verbose("%comspec% /c ant.bat debug -f "+ROOT+"\\build.xml 2>&1");
-    }
-}
-
-function log() {
-    // filter out nativeGetEnabledTags spam from latest sdk bug.
-    shell.Run("%comspec% /c adb logcat | grep -v nativeGetEnabledTags");
-}
-
-function run(target, build_type) {
-    var use_target = false;
-    if (!target) {
-        Log("WARNING: [ --target=<ID> | --emulator | --device ] not specified, using defaults");
-    }
-    // build application
-    build(build_type);
-    // attempt to deploy to connected device 
-    var devices = get_devices();
-    if (devices.length > 0 || target == "--device") {
-        if (target) {
-            if (target.substr(0,9) == "--target=") {
-                install_device(target.split('--target=').join(''))
-            } else if (target == "--device") {
-                install_device();
-            } else {
-                Log("Did not regognize " + target + " as a run option.", true);
-                WScript.Quit(2);
-            }
-        }
-        else {
-            Log("WARNING: [ --target=<ID> | --emulator | --device ] not specified, using defaults");
-            install_device();
-        }
-    }
-    else {
-        var emulators = get_started_emulators();
-        if (emulators.length > 0) {
-            install_emulator();
-        }
-        else {
-            var emulator_images = get_emulator_images();
-            if (emulator_images.length < 1) {
-                Log('No emulators found, if you would like to create an emulator follow the instructions', true);
-                Log(' provided here : http://developer.android.com/tools/devices/index.html', true);
-                Log(' Or run \'android create avd --name <name> --target <targetID>\' in on the command line.', true);
-                WScript.Quit(2);
-            }
-            start_emulator(emulator_images[0].split(' ')[0]);
-            emulators = get_started_emulators();
-            if (emulators.length > 0) {
-                install_emulator();
-            }
-            else {
-                Log("Error : emulator failed to start.", true);
-                WScript.Quit(2);
-            }
-        }
-    }
-}
-
-var args = WScript.Arguments;
-if (args.count() == 0) {
-    Log("Error: no args provided.");
-    WScript.Quit(2);
-}
-else {
-    if (args(0) == "build") {
-        if (args.Count() > 1) {
-            build(args(1))
-        } else {
-            build();
-        }
-    } else if (args(0) == "clean") {
-        clean();
-    } else if (args(0) == "list-devices") {
-        list_devices();
-    } else if (args(0) == "list-emulator-images") {
-        list_emulator_images();
-    } else if (args(0) == "list-started-emulators") {
-        list_started_emulators();
-    } else if (args(0) == "start-emulator") {
-        if (args.Count() > 1) {
-            start_emulator(args(1))
-        } else {
-            start_emulator();
-        }
-    } else if (args(0) == "log") {
-        log();
-    } else if (args(0) == "install-emulator") {
-        if (args.Count() == 2) {
-            if (args(1).substr(0,9) == "--target=") {
-                install_emulator(args(1).split('--target=').join(''));
-            } else {
-                Log('Error: \"' + args(1) + '\" is not recognized as an install option', true);
-                WScript.Quit(2);
-            }
-        } else {
-            install_emulator();
-        }
-    } else if (args(0) == "install-device") {
-        if (args.Count() == 2) {
-            if (args(1).substr(0,9) == "--target=") {
-                install_device(args(1).split('--target=').join(''));
-            } else {
-                Log('Error: \"' + args(1) + '\" is not recognized as an install option', true);
-                WScript.Quit(2);
-            }
-        } else {
-            install_device();
-        }
-    } else if (args(0) == "run") {
-        if (args.Count() == 3) {
-            run(args(1), args(2));
-        }
-        else if (args.Count() == 2) {
-            if (args(1).substr(0,9) == "--target=" ||
-               args(1) == "--emulator" ||
-               args(1) == "--device") {
-                run(args(1));
-            } else if (args(1) == "--debug" ||
-                       args(1) == "--release" ||
-                       args(1) == "--nobuild") {
-                run(null, args(1))
-            } else {
-                Log('Error: \"' + args(1) + '\" is not recognized as a run option', true);
-                WScript.Quit(2);
-            }
-        }
-        else {
-            run();
-        }
-    } else {
-        Log('Error: \"' + args(0) + '\" is not recognized as a tooling command', true);
-        WScript.Quit(2);
-    }
-}
-

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/lib/install-device
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/install-device b/lib/cordova-android/bin/templates/cordova/lib/install-device
deleted file mode 100755
index 604b5ae..0000000
--- a/lib/cordova-android/bin/templates/cordova/lib/install-device
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-# 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.
-
-set -e
-
-CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
-
-bash "$CORDOVA_LIB_PATH"/cordova install-device "$@"
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/lib/install-device.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/install-device.bat b/lib/cordova-android/bin/templates/cordova/lib/install-device.bat
deleted file mode 100644
index 52d9775..0000000
--- a/lib/cordova-android/bin/templates/cordova/lib/install-device.bat
+++ /dev/null
@@ -1,9 +0,0 @@
-@ECHO OFF
-SET full_path=%~dp0
-IF EXIST %full_path%cordova.js (
-    cscript "%full_path%cordova.js" install-device %* //nologo
-) ELSE (
-    ECHO. 
-    ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
-    EXIT /B 1
-)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/lib/install-emulator
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/install-emulator b/lib/cordova-android/bin/templates/cordova/lib/install-emulator
deleted file mode 100755
index 105e2ee..0000000
--- a/lib/cordova-android/bin/templates/cordova/lib/install-emulator
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-# 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.
-
-set -e
-
-CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
-
-bash "$CORDOVA_LIB_PATH"/cordova install-emulator "$@"
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/lib/install-emulator.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/install-emulator.bat b/lib/cordova-android/bin/templates/cordova/lib/install-emulator.bat
deleted file mode 100644
index d11a7be..0000000
--- a/lib/cordova-android/bin/templates/cordova/lib/install-emulator.bat
+++ /dev/null
@@ -1,9 +0,0 @@
-@ECHO OFF
-SET full_path=%~dp0
-IF EXIST %full_path%cordova.js (
-    cscript "%full_path%cordova.js" install-emulator %* //nologo
-) ELSE (
-    ECHO. 
-    ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
-    EXIT /B 1
-)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/lib/list-devices
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-devices b/lib/cordova-android/bin/templates/cordova/lib/list-devices
deleted file mode 100755
index 7a5b2f5..0000000
--- a/lib/cordova-android/bin/templates/cordova/lib/list-devices
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-# 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.
-
-set -e
-
-CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
-
-bash "$CORDOVA_LIB_PATH"/cordova list-devices
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/lib/list-devices.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-devices.bat b/lib/cordova-android/bin/templates/cordova/lib/list-devices.bat
deleted file mode 100644
index c146f10..0000000
--- a/lib/cordova-android/bin/templates/cordova/lib/list-devices.bat
+++ /dev/null
@@ -1,9 +0,0 @@
-@ECHO OFF
-SET full_path=%~dp0
-IF EXIST %full_path%cordova.js (
-    cscript "%full_path%cordova.js" list-devices //nologo
-) ELSE (
-    ECHO. 
-    ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
-    EXIT /B 1
-)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images b/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images
deleted file mode 100755
index db8e563..0000000
--- a/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-# 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.
-
-set -e
-
-CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
-
-bash "$CORDOVA_LIB_PATH"/cordova list-emulator-images
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images.bat b/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images.bat
deleted file mode 100644
index 172520b..0000000
--- a/lib/cordova-android/bin/templates/cordova/lib/list-emulator-images.bat
+++ /dev/null
@@ -1,9 +0,0 @@
-@ECHO OFF
-SET full_path=%~dp0
-IF EXIST %full_path%cordova.js (
-    cscript "%full_path%cordova.js" list-emulator-images //nologo
-) ELSE (
-    ECHO. 
-    ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
-    EXIT /B 1
-)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators b/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators
deleted file mode 100755
index 7911763..0000000
--- a/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-# 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.
-
-set -e
-
-CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
-
-bash "$CORDOVA_LIB_PATH"/cordova list-started-emulators
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators.bat b/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators.bat
deleted file mode 100644
index f1b3c5d..0000000
--- a/lib/cordova-android/bin/templates/cordova/lib/list-started-emulators.bat
+++ /dev/null
@@ -1,9 +0,0 @@
-@ECHO OFF
-SET full_path=%~dp0
-IF EXIST %full_path%cordova.js (
-    cscript "%full_path%cordova.js" list-started-emulators //nologo
-) ELSE (
-    ECHO. 
-    ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
-    EXIT /B 1
-)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/lib/start-emulator
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/start-emulator b/lib/cordova-android/bin/templates/cordova/lib/start-emulator
deleted file mode 100755
index 8e8964d..0000000
--- a/lib/cordova-android/bin/templates/cordova/lib/start-emulator
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-# 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.
-
-set -e
-
-CORDOVA_LIB_PATH=$( cd "$( dirname "$0" )" && pwd )
-
-bash "$CORDOVA_LIB_PATH"/cordova start-emulator "$@"
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/lib/start-emulator.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/lib/start-emulator.bat b/lib/cordova-android/bin/templates/cordova/lib/start-emulator.bat
deleted file mode 100644
index 4f3fb5d..0000000
--- a/lib/cordova-android/bin/templates/cordova/lib/start-emulator.bat
+++ /dev/null
@@ -1,9 +0,0 @@
-@ECHO OFF
-SET full_path=%~dp0
-IF EXIST %full_path%cordova.js (
-    cscript "%full_path%cordova.js" start-emulator %* //nologo
-) ELSE (
-    ECHO. 
-    ECHO ERROR: Could not find 'cordova.js' in cordova/lib, aborting...>&2
-    EXIT /B 1
-)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee0a5029/lib/cordova-android/bin/templates/cordova/log
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/log b/lib/cordova-android/bin/templates/cordova/log
index 01fe107..087a200 100755
--- a/lib/cordova-android/bin/templates/cordova/log
+++ b/lib/cordova-android/bin/templates/cordova/log
@@ -1,4 +1,3 @@
-#!/bin/bash
 # 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
@@ -16,8 +15,10 @@
 # specific language governing permissions and limitations
 # under the License.
 
+#!/bin/bash
+
 set -e
 
 CORDOVA_PATH=$( cd "$( dirname "$0" )/.." && pwd )
 
-bash "$CORDOVA_PATH"/cordova/lib/cordova log "$@"
+bash "$CORDOVA_PATH"/cordova/cordova log


[11/43] git commit: Move www/ and merges/ into app/.

Posted by an...@apache.org.
Move www/ and merges/ into app/.

The structure is now:
app/
  merges/
    android/
    ios/
  www/
  config.xml

All code, tests and docs are updated and everything is still working. This
is a breaking change for old projects, but it's fairly easy to perform the
move manually:
$ mkdir app
$ mv www/config.xml app
$ mv www app
$ mv merges app


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

Branch: refs/heads/master
Commit: 740ff28d73e0275a47cb16ff86b2d8542b0662fa
Parents: 2f39840
Author: Braden Shepherdson <br...@gmail.com>
Authored: Tue Apr 9 10:12:56 2013 -0400
Committer: Braden Shepherdson <br...@gmail.com>
Committed: Tue Apr 9 11:11:34 2013 -0400

----------------------------------------------------------------------
 README.md                                          |   81 +-
 bootstrap.js                                       |    4 +-
 spec/config_parser.spec.js                         |    3 +-
 spec/create.spec.js                                |    5 +-
 spec/metadata/android_parser.spec.js               |    8 +-
 spec/metadata/blackberry_parser.spec.js            |   10 +-
 spec/metadata/ios_parser.spec.js                   |    8 +-
 spec/platform.spec.js                              |    4 +-
 spec/serve.spec.js                                 |    2 +-
 src/compile.js                                     |    3 +-
 src/create.js                                      |   10 +-
 src/emulate.js                                     |    2 +-
 src/metadata/android_parser.js                     |    6 +-
 src/metadata/blackberry_parser.js                  |   10 +-
 src/metadata/ios_parser.js                         |    4 +-
 src/platform.js                                    |    6 +-
 src/plugin.js                                      |    4 +-
 src/prepare.js                                     |    2 +-
 src/serve.js                                       |    2 +-
 src/util.js                                        |    9 +
 templates/app/config.xml                           |   49 +
 templates/app/www/css/index.css                    |  100 +
 templates/app/www/img/cordova.png                  |  Bin 0 -> 19932 bytes
 templates/app/www/index.html                       |   24 +
 templates/app/www/js/index.js                      |   20 +
 templates/app/www/res/icon/cordova_128.png         |  Bin 0 -> 11401 bytes
 templates/app/www/res/icon/cordova_16.png          |  Bin 0 -> 1699 bytes
 templates/app/www/res/icon/cordova_24.png          |  Bin 0 -> 2215 bytes
 templates/app/www/res/icon/cordova_256.png         |  Bin 0 -> 27408 bytes
 templates/app/www/res/icon/cordova_32.png          |  Bin 0 -> 2843 bytes
 templates/app/www/res/icon/cordova_48.png          |  Bin 0 -> 4111 bytes
 templates/app/www/res/icon/cordova_512.png         |  Bin 0 -> 39830 bytes
 templates/app/www/res/icon/cordova_64.png          |  Bin 0 -> 5463 bytes
 templates/app/www/res/icon/cordova_android_36.png  |  Bin 0 -> 3096 bytes
 templates/app/www/res/icon/cordova_android_48.png  |  Bin 0 -> 4090 bytes
 templates/app/www/res/icon/cordova_android_72.png  |  Bin 0 -> 6080 bytes
 templates/app/www/res/icon/cordova_android_96.png  |  Bin 0 -> 7685 bytes
 templates/app/www/res/icon/cordova_bb_80.png       |  Bin 0 -> 7287 bytes
 templates/app/www/res/icon/cordova_ios_114.png     |  Bin 0 -> 7869 bytes
 templates/app/www/res/icon/cordova_ios_144.png     |  Bin 0 -> 11706 bytes
 templates/app/www/res/icon/cordova_ios_57.png      |  Bin 0 -> 3908 bytes
 templates/app/www/res/icon/cordova_ios_72.png      |  Bin 0 -> 4944 bytes
 .../app/www/res/screen/android_hdpi_landscape.png  |  Bin 0 -> 218302 bytes
 .../app/www/res/screen/android_hdpi_portrait.png   |  Bin 0 -> 222148 bytes
 .../app/www/res/screen/android_ldpi_landscape.png  |  Bin 0 -> 42616 bytes
 .../app/www/res/screen/android_ldpi_portrait.png   |  Bin 0 -> 42034 bytes
 .../app/www/res/screen/android_mdpi_landscape.png  |  Bin 0 -> 92347 bytes
 .../app/www/res/screen/android_mdpi_portrait.png   |  Bin 0 -> 90555 bytes
 .../app/www/res/screen/android_xhdpi_landscape.png |  Bin 0 -> 489604 bytes
 .../app/www/res/screen/android_xhdpi_portrait.png  |  Bin 0 -> 504508 bytes
 .../www/res/screen/blackberry_transparent_300.png  |  Bin 0 -> 15823 bytes
 .../www/res/screen/blackberry_transparent_400.png  |  Bin 0 -> 11001 bytes
 templates/app/www/res/screen/ipad_landscape.png    |  Bin 0 -> 407370 bytes
 templates/app/www/res/screen/ipad_portrait.png     |  Bin 0 -> 422441 bytes
 .../app/www/res/screen/ipad_retina_landscape.png   |  Bin 0 -> 1534088 bytes
 .../app/www/res/screen/ipad_retina_portrait.png    |  Bin 0 -> 1610434 bytes
 templates/app/www/res/screen/iphone_landscape.png  |  Bin 0 -> 92301 bytes
 templates/app/www/res/screen/iphone_portrait.png   |  Bin 0 -> 93897 bytes
 .../app/www/res/screen/iphone_retina_landscape.png |  Bin 0 -> 339639 bytes
 .../app/www/res/screen/iphone_retina_portrait.png  |  Bin 0 -> 350593 bytes
 .../app/www/res/screen/windows_phone_portrait.jpg  |  Bin 0 -> 11483 bytes
 templates/app/www/spec.html                        |   50 +
 templates/app/www/spec/helper.js                   |   11 +
 templates/app/www/spec/index.js                    |   49 +
 .../app/www/spec/lib/jasmine-1.2.0/MIT.LICENSE     |   20 +
 .../app/www/spec/lib/jasmine-1.2.0/jasmine-html.js |  616 ++++
 .../app/www/spec/lib/jasmine-1.2.0/jasmine.css     |   81 +
 .../app/www/spec/lib/jasmine-1.2.0/jasmine.js      | 2529 +++++++++++++++
 templates/www/config.xml                           |   49 -
 templates/www/css/index.css                        |  100 -
 templates/www/img/cordova.png                      |  Bin 19932 -> 0 bytes
 templates/www/index.html                           |   24 -
 templates/www/js/index.js                          |   20 -
 templates/www/res/icon/cordova_128.png             |  Bin 11401 -> 0 bytes
 templates/www/res/icon/cordova_16.png              |  Bin 1699 -> 0 bytes
 templates/www/res/icon/cordova_24.png              |  Bin 2215 -> 0 bytes
 templates/www/res/icon/cordova_256.png             |  Bin 27408 -> 0 bytes
 templates/www/res/icon/cordova_32.png              |  Bin 2843 -> 0 bytes
 templates/www/res/icon/cordova_48.png              |  Bin 4111 -> 0 bytes
 templates/www/res/icon/cordova_512.png             |  Bin 39830 -> 0 bytes
 templates/www/res/icon/cordova_64.png              |  Bin 5463 -> 0 bytes
 templates/www/res/icon/cordova_android_36.png      |  Bin 3096 -> 0 bytes
 templates/www/res/icon/cordova_android_48.png      |  Bin 4090 -> 0 bytes
 templates/www/res/icon/cordova_android_72.png      |  Bin 6080 -> 0 bytes
 templates/www/res/icon/cordova_android_96.png      |  Bin 7685 -> 0 bytes
 templates/www/res/icon/cordova_bb_80.png           |  Bin 7287 -> 0 bytes
 templates/www/res/icon/cordova_ios_114.png         |  Bin 7869 -> 0 bytes
 templates/www/res/icon/cordova_ios_144.png         |  Bin 11706 -> 0 bytes
 templates/www/res/icon/cordova_ios_57.png          |  Bin 3908 -> 0 bytes
 templates/www/res/icon/cordova_ios_72.png          |  Bin 4944 -> 0 bytes
 .../www/res/screen/android_hdpi_landscape.png      |  Bin 218302 -> 0 bytes
 templates/www/res/screen/android_hdpi_portrait.png |  Bin 222148 -> 0 bytes
 .../www/res/screen/android_ldpi_landscape.png      |  Bin 42616 -> 0 bytes
 templates/www/res/screen/android_ldpi_portrait.png |  Bin 42034 -> 0 bytes
 .../www/res/screen/android_mdpi_landscape.png      |  Bin 92347 -> 0 bytes
 templates/www/res/screen/android_mdpi_portrait.png |  Bin 90555 -> 0 bytes
 .../www/res/screen/android_xhdpi_landscape.png     |  Bin 489604 -> 0 bytes
 .../www/res/screen/android_xhdpi_portrait.png      |  Bin 504508 -> 0 bytes
 .../www/res/screen/blackberry_transparent_300.png  |  Bin 15823 -> 0 bytes
 .../www/res/screen/blackberry_transparent_400.png  |  Bin 11001 -> 0 bytes
 templates/www/res/screen/ipad_landscape.png        |  Bin 407370 -> 0 bytes
 templates/www/res/screen/ipad_portrait.png         |  Bin 422441 -> 0 bytes
 templates/www/res/screen/ipad_retina_landscape.png |  Bin 1534088 -> 0 bytes
 templates/www/res/screen/ipad_retina_portrait.png  |  Bin 1610434 -> 0 bytes
 templates/www/res/screen/iphone_landscape.png      |  Bin 92301 -> 0 bytes
 templates/www/res/screen/iphone_portrait.png       |  Bin 93897 -> 0 bytes
 .../www/res/screen/iphone_retina_landscape.png     |  Bin 339639 -> 0 bytes
 .../www/res/screen/iphone_retina_portrait.png      |  Bin 350593 -> 0 bytes
 .../www/res/screen/windows_phone_portrait.jpg      |  Bin 11483 -> 0 bytes
 templates/www/spec.html                            |   50 -
 templates/www/spec/helper.js                       |   11 -
 templates/www/spec/index.js                        |   49 -
 templates/www/spec/lib/jasmine-1.2.0/MIT.LICENSE   |   20 -
 .../www/spec/lib/jasmine-1.2.0/jasmine-html.js     |  616 ----
 templates/www/spec/lib/jasmine-1.2.0/jasmine.css   |   81 -
 templates/www/spec/lib/jasmine-1.2.0/jasmine.js    | 2529 ---------------
 116 files changed, 3648 insertions(+), 3633 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index f177fbd..291c037 100644
--- a/README.md
+++ b/README.md
@@ -53,45 +53,47 @@ A Cordova application built with cordova-cli will have the following directory s
 
     myApp/
     |--.cordova/
-    |-- merges/
-    | |-- android/
-    | |-- blackberry/
-    | `-- ios/
+    |-- app/
+    | |-- merges/
+    | | |-- android/
+    | | |-- blackberry/
+    | | `-- ios/
+    | |-- www/
+    | `-- config.xml
     |-- platforms/
     | |-- android/
     | |-- blackberry/
     | `-- ios/
-    |-- plugins/
-    `-- www/
+    `-- plugins/
 
 ## .cordova/
 This directory identifies a tree as a cordova project. Simple configuration information is stored in here (such as BlackBerry environment variables).
 
 Commands other than `create` operate against the project directory itself, rather than the current directory - a search up the current directory's parents is made to find the project directory. Thus, any command (other than `create`) can be used from any subdirectory whose parent is a cordova project directory (same as git).
 
-## merges/
-Platform-specific web assets (HTML, CSS and JavaScript files) are contained within appropriate subfolders in this directory. These are deployed during a `prepare` to the appropriate native directory.  Files placed under `merges/` will override matching files in the `www/` folder for the relevant platform. A quick example, assuming a project structure of:
+## app/
 
-    merges/
-    |-- ios/
-    | `-- app.js
-    |-- android/
-    | `-- android.js
-    www/
-      `-- app.js
+Contains your app-specific content: its `www/` files, any `merges/`, and the `config.xml`. If you want to keep your app in source control, this directory should be the top of the repository.
 
-After building the Android and iOS projects, the Android application will contain both `app.js` and `android.js`. However, the iOS application will only contain an `app.js`, and it will override the "common" `app.js` located inside the `www/` folder above.
 
-## platforms/
-Platforms added to your application will have the native application project structures laid out within this directory.
+### app/merges/
+Platform-specific web assets (HTML, CSS and JavaScript files) are contained within appropriate subfolders in this directory. These are deployed during a `prepare` to the appropriate native directory.  Files placed under `app/merges/` will override matching files in the `app/www/` folder for the relevant platform. A quick example, assuming a project structure of:
 
-## plugins/
-Any added plugins will be extracted or copied into this directory.
+    app/
+    |-- merges/
+    | |-- ios/
+    | | `-- app.js
+    | `-- android/
+    |   `-- android.js
+    `--www/
+      `-- app.js
 
-## www/
-Contains the project's web artifacts, such as .html, .css and .js files. These are your main application assets. The config.xml file within this directory is very important; read on to the next section!
+After building the Android and iOS projects, the Android application will contain both `app.js` and `android.js`. However, the iOS application will only contain an `app.js`, and it will be the one from `app/merges/ios/app.js`, overriding the "common" `app.js` located inside `app/www/`.
 
-### Your Blanket: www/config.xml 
+### app/www/
+Contains the project's web artifacts, such as .html, .css and .js files. These are your main application assets. They will be copied on a `cordova prepare` to each platform's www directory.
+
+### Your Blanket: app/config.xml
 
 This file is what you should be editing to modify your application's metadata. Any time you run any cordova-cli commands, the tool will look at the contents of `config.xml` and use all relevant info from this file to define native application information. cordova-cli supports changing your application's data via the following elements inside the `config.xml` file:
 
@@ -100,6 +102,12 @@ This file is what you should be editing to modify your application's metadata. A
 - The whitelist can be modified using the `<access>` elements. Make sure the `origin` attribute of your `<access>` element points to a valid URL (you can use `*` as wildcard). For more information on the whitelisting syntax, see the [docs.phonegap.com](http://docs.phonegap.com/en/2.2.0/guide_whitelist_index.md.html#Domain%20Whitelist%20Guide). You can use either attribute `uri` ([BlackBerry-proprietary](https://developer.blackberry.com/html5/documentation/access_element_834677_11.html)) or `origin` ([standards-compliant](http://www.w3.org/TR/widgets-access/#attributes)) to denote the domain.
 - Platform-specific preferences can be customized via `<preference>` tags. See [docs.phonegap.com](http://docs.phonegap.com/en/2.3.0/guide_project-settings_index.md.html#Project%20Settings) for a list of preferences you can use.
 
+## platforms/
+Platforms added to your application will have the native application project structures laid out within this directory.
+
+## plugins/
+Any added plugins will be extracted or copied into this directory.
+
 # Hooks
 
 Projects created by cordova-cli have `before` and `after` hooks for each [project command](#project_commands). There are two types of hooks: project-specific ones and module-level ones.
@@ -130,19 +138,20 @@ This example shows how to create a project from scratch named KewlApp with iOS a
 The directory structure of KewlApp now looks like this:
 
     KewlApp/
-    |- .cordova/
-    |- mergess/
-       |- android/
-       `- ios/
-    |- platforms/
-       |- android/
-       |  `- …
-       `- ios/
-          `- …
-    |- plugins/
-       `- Kewlio/
-    `- www/
-       `- index.html
+    |-- .cordova/
+    |-- app/
+    | |-- merges/
+    | | |-- android/
+    | | `-- ios/
+    | `- www/
+    |    `-- index.html
+    |-- platforms/
+    | |-- android/
+    | | `-- …
+    | `-- ios/
+    |   `-- …
+    `-- plugins/
+      `-- Kewlio/
 
 # Contributing
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/bootstrap.js
----------------------------------------------------------------------
diff --git a/bootstrap.js b/bootstrap.js
index f96df76..2012bbd 100644
--- a/bootstrap.js
+++ b/bootstrap.js
@@ -50,7 +50,7 @@ shell.rm('-rf', cordovaDir);
 create(cordovaDir);
 var platformsDir = path.join(cordovaDir, 'platforms');
 // kill the stupid spec shit!
-shell.rm('-rf', path.join(cordovaDir, 'www', 'spec'));
+shell.rm('-rf', path.join(cordovaDir, 'app', 'www', 'spec'));
 
 var end = n(platforms.length, function() {
     // Check that we are installing globally into a root-only directory.
@@ -91,7 +91,7 @@ platforms.forEach(function(platform) {
                     // copy over to full cordova project test fixture
                     shell.mkdir('-p', platformDir);
                     shell.cp('-rf', path.join(fix_path, '*'), platformDir);
-                    shell.mkdir('-p',path.join(cordovaDir,'merges',platform));
+                    shell.mkdir('-p',path.join(util.appDir(cordovaDir),'merges',platform));
 
                     // set permissions on executables
                     var scripts_path = path.join(fix_path, 'cordova');

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/spec/config_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/config_parser.spec.js b/spec/config_parser.spec.js
index 99bc717..3745c90 100644
--- a/spec/config_parser.spec.js
+++ b/spec/config_parser.spec.js
@@ -24,7 +24,8 @@ var cordova = require('../cordova'),
     config_parser = require('../src/config_parser'),
     tempDir = path.join(__dirname, '..', 'temp'),
     et = require('elementtree'),
-    xml = path.join(tempDir, 'www', 'config.xml');
+    util = require('../src/util'),
+    xml = util.projectConfig(tempDir);
 
 
 describe('config.xml parser', function () {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/spec/create.spec.js
----------------------------------------------------------------------
diff --git a/spec/create.spec.js b/spec/create.spec.js
index fcb3e76..da4e544 100644
--- a/spec/create.spec.js
+++ b/spec/create.spec.js
@@ -2,6 +2,7 @@ var cordova = require('../cordova'),
     path    = require('path'),
     shell   = require('shelljs'),
     fs      = require('fs'),
+    util    = require('../src/util'),
     tempDir = path.join(__dirname, '..', 'temp');
 
 describe('create command', function () {
@@ -54,14 +55,14 @@ describe('create command', function () {
 
         expect(fs.lstatSync(path.join(tempDir, '.cordova', 'config.json')).isFile()).toBe(true);
 
-        expect(fs.readFileSync(path.join(tempDir, 'www', 'config.xml')).toString('utf8')).toMatch(/<name>balls<\/name>/);
+        expect(fs.readFileSync(util.projectConfig(tempDir)).toString('utf8')).toMatch(/<name>balls<\/name>/);
     });
     it('should create a cordova project in the specified dir with specified name and id if provided', function() {
         cordova.create(tempDir, "birdy.nam.nam", "numnum");
 
         expect(fs.lstatSync(path.join(tempDir, '.cordova', 'config.json')).isFile()).toBe(true);
 
-        var config = fs.readFileSync(path.join(tempDir, 'www', 'config.xml')).toString('utf8');
+        var config = fs.readFileSync(util.projectConfig(tempDir)).toString('utf8');
         expect(config).toMatch(/<name>numnum<\/name>/);
         expect(config).toMatch(/id="birdy\.nam\.nam"/);
     });

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/spec/metadata/android_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/metadata/android_parser.spec.js b/spec/metadata/android_parser.spec.js
index d051c6f..b7d106c 100644
--- a/spec/metadata/android_parser.spec.js
+++ b/spec/metadata/android_parser.spec.js
@@ -30,7 +30,7 @@ var android_parser = require('../../src/metadata/android_parser'),
     project_path = path.join(projects_path, 'cordova'),
     android_project_path = path.join(project_path, 'platforms', 'android');
 
-var www_config = path.join(project_path, 'www', 'config.xml');
+var www_config = util.projectConfig(project_path);
 var original_www_config = fs.readFileSync(www_config, 'utf-8');
 
 describe('android project parser', function() {
@@ -158,7 +158,7 @@ describe('android project parser', function() {
         });
         describe('update_www method', function() {
             it('should update all www assets', function() {
-                var newFile = path.join(project_path, 'www', 'somescript.js');
+                var newFile = path.join(util.projectWww(project_path), 'somescript.js');
                 this.after(function() {
                     shell.rm('-f', newFile);
                 });
@@ -173,7 +173,7 @@ describe('android project parser', function() {
         });
 
         describe('update_overrides method',function() {
-            var mergesPath = path.join(project_path, 'merges', 'android');
+            var mergesPath = path.join(util.appDir(project_path), 'merges', 'android');
             var newFile = path.join(mergesPath, 'merge.js');
             beforeEach(function() {
                 shell.mkdir('-p', mergesPath);
@@ -188,7 +188,7 @@ describe('android project parser', function() {
             });
 
             it('should copy a file from merges over a file in www', function() {
-                var newFileWWW = path.join(project_path, 'www','merge.js');
+                var newFileWWW = path.join(util.projectWww(project_path), 'merge.js');
                 fs.writeFileSync(newFileWWW, 'var foo=1;', 'utf-8');
                 this.after(function() {
                     shell.rm('-rf', newFileWWW);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/spec/metadata/blackberry_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/metadata/blackberry_parser.spec.js b/spec/metadata/blackberry_parser.spec.js
index 12d5294..ada1727 100644
--- a/spec/metadata/blackberry_parser.spec.js
+++ b/spec/metadata/blackberry_parser.spec.js
@@ -30,7 +30,7 @@ var blackberry_parser = require('../../src/metadata/blackberry_parser'),
     project_path = path.join(projects_path, 'cordova'),
     blackberry_project_path = path.join(project_path, 'platforms', 'blackberry');
 
-var www_config = path.join(project_path, 'www', 'config.xml');
+var www_config = util.projectConfig(project_path);
 var original_www_config = fs.readFileSync(www_config, 'utf-8');
 
 describe('blackberry project parser', function() {
@@ -128,7 +128,7 @@ describe('blackberry project parser', function() {
 
         describe('update_www method', function() {
             it('should update all www assets', function() {
-                var newFile = path.join(project_path, 'www', 'somescript.js');
+                var newFile = path.join(util.projectWww(project_path), 'somescript.js');
                 this.after(function() {
                     shell.rm('-f', newFile);
                 });
@@ -137,7 +137,7 @@ describe('blackberry project parser', function() {
                 expect(fs.existsSync(path.join(blackberry_project_path, 'www', 'somescript.js'))).toBe(true);
             });
             it('should not overwrite the blackberry-specific config.xml', function() {
-                var www_cfg = fs.readFileSync(path.join(project_path, 'www', 'config.xml'), 'utf-8');
+                var www_cfg = fs.readFileSync(util.projectConfig(project_path), 'utf-8');
                 parser.update_www();
                 var bb_cfg = fs.readFileSync(blackberry_config, 'utf-8');
                 expect(bb_cfg).not.toBe(www_cfg);
@@ -145,7 +145,7 @@ describe('blackberry project parser', function() {
         });
 
         describe('update_overrides method',function() {
-            var mergesPath = path.join(project_path, 'merges', 'blackberry');
+            var mergesPath = path.join(util.appDir(project_path), 'merges', 'blackberry');
             var newFile = path.join(mergesPath, 'merge.js');
             beforeEach(function() {
                 shell.mkdir('-p', mergesPath);
@@ -161,7 +161,7 @@ describe('blackberry project parser', function() {
             });
 
             it('should copy a file from merges over a file in www', function() {
-                var newFileWWW = path.join(project_path, 'www','merge.js');
+                var newFileWWW = path.join(util.projectWww(project_path), 'merge.js');
                 fs.writeFileSync(newFileWWW, 'var foo=1;', 'utf-8');
                 this.after(function() {
                     shell.rm('-rf', newFileWWW);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/spec/metadata/ios_parser.spec.js
----------------------------------------------------------------------
diff --git a/spec/metadata/ios_parser.spec.js b/spec/metadata/ios_parser.spec.js
index dbd4816..e1f92a6 100644
--- a/spec/metadata/ios_parser.spec.js
+++ b/spec/metadata/ios_parser.spec.js
@@ -30,7 +30,7 @@ ios_path = path.join(projects_path, 'native', 'ios_fixture'),
     project_path = path.join(projects_path, 'cordova'),
     ios_project_path = path.join(project_path, 'platforms', 'ios');
 
-var www_config = path.join(project_path, 'www', 'config.xml');
+var www_config = util.projectConfig(project_path);
 var original_www_config = fs.readFileSync(www_config, 'utf-8');
 
 describe('ios project parser', function () {
@@ -147,7 +147,7 @@ describe('ios project parser', function () {
 
         describe('update_www method', function () {
             it('should update all www assets', function () {
-                var newFile = path.join(project_path, 'www', 'somescript.js');
+                var newFile = path.join(util.projectWww(project_path), 'somescript.js');
                 this.after(function () {
                     shell.rm('-f', newFile);
                 });
@@ -162,7 +162,7 @@ describe('ios project parser', function () {
         });
 
         describe('update_overrides method', function () {
-            var mergesPath = path.join(project_path, 'merges', 'ios');
+            var mergesPath = path.join(util.appDir(project_path), 'merges', 'ios');
             var newFile = path.join(mergesPath, 'merge.js');
             beforeEach(function() {
                 shell.mkdir('-p', mergesPath);
@@ -178,7 +178,7 @@ describe('ios project parser', function () {
             });
 
             it('should copy a file from merges over a file in www', function () {
-                var newFileWWW = path.join(project_path, 'www', 'merge.js');
+                var newFileWWW = path.join(util.projectWww(project_path), 'merge.js');
                 fs.writeFileSync(newFileWWW, 'var foo=1;', 'utf-8');
                 this.after(function () {
                     shell.rm('-rf', newFileWWW);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/spec/platform.spec.js
----------------------------------------------------------------------
diff --git a/spec/platform.spec.js b/spec/platform.spec.js
index b8dedec..c2c173f 100644
--- a/spec/platform.spec.js
+++ b/spec/platform.spec.js
@@ -136,7 +136,7 @@ describe('platform command', function() {
                 shell.mkdir('-p', a_path);
                 fs.writeFileSync(path.join(a_path, 'poo.xcodeproj'), 'hi', 'utf-8');
                 shell.mkdir('-p', path.join(a_path, 'poo'));
-                shell.cp(path.join(cordova_project, 'www', 'config.xml'), path.join(a_path, 'poo', 'config.xml'));
+                shell.cp(util.projectConfig(cordova_project), path.join(a_path, 'poo', 'config.xml'));
                 sh.mostRecentCall.args[2](0, '');
             };
             beforeEach(function() {
@@ -166,7 +166,7 @@ describe('platform command', function() {
                 shell.mkdir('-p', path.join(a_path, 'www'));
                 fs.writeFileSync(path.join(a_path, 'project.properties'), 'hi', 'utf-8');
                 fs.writeFileSync(path.join(a_path, 'build.xml'), 'hi', 'utf-8');
-                shell.cp(path.join(cordova_project, 'www', 'config.xml'), path.join(a_path, 'www', 'config.xml'));
+                shell.cp(util.projectConfig(cordova_project), path.join(a_path, 'www', 'config.xml'));
                 sh.mostRecentCall.args[2](0, '');
             };
             beforeEach(function() {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/spec/serve.spec.js
----------------------------------------------------------------------
diff --git a/spec/serve.spec.js b/spec/serve.spec.js
index 8d00cab..080c273 100644
--- a/spec/serve.spec.js
+++ b/spec/serve.spec.js
@@ -119,7 +119,7 @@ xdescribe('serve command', function() {
 
         it('should serve from top-level www if the file exists there', function() {
             var payload = 'This is test file.';
-            fs.writeFileSync(path.join(tempDir, 'www', 'test.html'), payload);
+            fs.writeFileSync(path.join(util.projectWww(tempDir), 'test.html'), payload);
             test_serve('android', '/test.html', payload)();
         });
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/src/compile.js
----------------------------------------------------------------------
diff --git a/src/compile.js b/src/compile.js
index 521451f..0e8951a 100644
--- a/src/compile.js
+++ b/src/compile.js
@@ -58,8 +58,7 @@ module.exports = function compile(platforms, callback) {
         throw new Error('Current working directory is not a Cordova-based project.');
     }
 
-    var xml = path.join(projectRoot, 'www', 'config.xml');
-    var assets = path.join(projectRoot, 'www');
+    var xml = cordova_util.projectConfig(projectRoot);
     var cfg = new config_parser(xml);
 
     if (arguments.length === 0 || (platforms instanceof Array && platforms.length === 0)) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/src/create.js
----------------------------------------------------------------------
diff --git a/src/create.js b/src/create.js
index 0f7c8a6..66ab225 100644
--- a/src/create.js
+++ b/src/create.js
@@ -21,7 +21,8 @@ var path          = require('path'),
     fs            = require('fs'),
     shell         = require('shelljs'),
     help          = require('./help'),
-    config_parser = require('./config_parser');
+    config_parser = require('./config_parser'),
+    util          = require('./util');
 
 var DEFAULT_NAME = "HelloCordova",
     DEFAULT_ID   = "io.cordova.hellocordova";
@@ -59,8 +60,9 @@ module.exports = function create (dir, id, name) {
     // Create basic project structure.
     shell.mkdir('-p', dotCordova);
     shell.mkdir('-p', path.join(dir, 'platforms'));
-    shell.mkdir('-p', path.join(dir, 'merges'));
     shell.mkdir('-p', path.join(dir, 'plugins'));
+    shell.mkdir('-p', path.join(dir, 'app'));
+    shell.mkdir('-p', path.join(dir, 'app', 'merges'));
     var hooks = path.join(dotCordova, 'hooks');
     shell.mkdir('-p', hooks);
 
@@ -95,10 +97,10 @@ module.exports = function create (dir, id, name) {
     }));
 
     // Copy in base template
-    shell.cp('-r', path.join(__dirname, '..', 'templates', 'www'), dir);
+    shell.cp('-r', path.join(__dirname, '..', 'templates', 'app'), dir);
 
     // Write out id and name to config.xml
-    var configPath = path.join(dir, 'www', 'config.xml');
+    var configPath = util.projectConfig(dir);
     var config = new config_parser(configPath);
     config.packageName(id);
     config.name(name);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/src/emulate.js
----------------------------------------------------------------------
diff --git a/src/emulate.js b/src/emulate.js
index 7acb441..523b5e0 100644
--- a/src/emulate.js
+++ b/src/emulate.js
@@ -60,7 +60,7 @@ module.exports = function emulate (platforms, callback) {
         throw new Error('Current working directory is not a Cordova-based project.');
     }
 
-    var xml = path.join(projectRoot, 'www', 'config.xml');
+    var xml = cordova_util.projectConfig(projectRoot);
     var cfg = new config_parser(xml);
 
     if (arguments.length === 0 || (platforms instanceof Array && platforms.length === 0)) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/src/metadata/android_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/android_parser.js b/src/metadata/android_parser.js
index 3dfaf22..70e952a 100644
--- a/src/metadata/android_parser.js
+++ b/src/metadata/android_parser.js
@@ -90,7 +90,7 @@ module.exports.prototype = {
         var android_cfg_xml = new config_parser(this.android_config);
         // clean out all existing access elements first
         android_cfg_xml.access.remove();
-        // add only the ones specified in the www/config.xml file
+        // add only the ones specified in the app/config.xml file
         config.access.get().forEach(function(uri) {
             android_cfg_xml.access.add(uri);
         });
@@ -128,7 +128,7 @@ module.exports.prototype = {
 
     update_www:function() {
         var projectRoot = util.isCordova(this.path);
-        var www = path.join(projectRoot, 'www');
+        var www = util.projectWww(projectRoot);
         var platformWww = path.join(this.path, 'assets');
         // remove stock platform assets
         shell.rm('-rf', this.www_dir());
@@ -144,7 +144,7 @@ module.exports.prototype = {
     // update the overrides folder into the www folder
     update_overrides:function() {
         var projectRoot = util.isCordova(this.path);
-        var merges_path = path.join(projectRoot, 'merges', 'android');
+        var merges_path = path.join(util.appDir(projectRoot), 'merges', 'android');
         if (fs.existsSync(merges_path)) {
             var overrides = path.join(merges_path, '*');
             shell.cp('-rf', overrides, this.www_dir());

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/src/metadata/blackberry_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/blackberry_parser.js b/src/metadata/blackberry_parser.js
index b2cad4b..5bd6d84 100644
--- a/src/metadata/blackberry_parser.js
+++ b/src/metadata/blackberry_parser.js
@@ -91,7 +91,7 @@ module.exports.prototype = {
 
     update_www:function() {
         var projectRoot = util.isCordova(this.path);
-        var www = path.join(projectRoot, 'www');
+        var www = util.projectWww(projectRoot);
         var platformWww = this.www_dir();
 
         var finalWww = path.join(this.path, 'finalwww');
@@ -110,12 +110,8 @@ module.exports.prototype = {
         shell.cp('-rf', path.join(platformWww, 'ext*'), finalWww);
         shell.cp('-rf', path.join(platformWww, 'res'), finalWww);
 
-        // Copy everything over from platform-agnostic www, except config.xml
-        var cfg_www = path.join(www, 'config.xml');
-        var temp_cfg = path.join(projectRoot, 'config.xml');
-        shell.mv(cfg_www, temp_cfg);
+        // Copy everything over from platform-agnostic www.
         shell.cp('-rf', path.join(www, '*'), finalWww);
-        shell.mv(temp_cfg, cfg_www);
 
         // Delete the old platform www, and move the final project over
         shell.rm('-rf', platformWww);
@@ -126,7 +122,7 @@ module.exports.prototype = {
     // update the overrides folder into the www folder
     update_overrides:function() {
         var projectRoot = util.isCordova(this.path);
-        var merges_path = path.join(projectRoot, 'merges', 'blackberry');
+        var merges_path = path.join(util.appDir(projectRoot), 'merges', 'blackberry');
         if (fs.existsSync(merges_path)) {
             var overrides = path.join(merges_path, '*');
             shell.cp('-rf', overrides, this.www_dir());

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/src/metadata/ios_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/ios_parser.js b/src/metadata/ios_parser.js
index ee235dc..e3b19fd 100644
--- a/src/metadata/ios_parser.js
+++ b/src/metadata/ios_parser.js
@@ -139,7 +139,7 @@ module.exports.prototype = {
 
     update_www:function() {
         var projectRoot = util.isCordova(this.path);
-        var www = path.join(projectRoot, 'www');
+        var www = util.projectWww(projectRoot);
         var project_www = this.www_dir();
 
         // remove the stock www folder
@@ -156,7 +156,7 @@ module.exports.prototype = {
     // update the overrides folder into the www folder
     update_overrides:function() {
         var projectRoot = util.isCordova(this.path);
-        var merges_path = path.join(projectRoot, 'merges', 'ios');
+        var merges_path = path.join(util.appDir(projectRoot), 'merges', 'ios');
         if (fs.existsSync(merges_path)) {
             var overrides = path.join(merges_path, '*');
             shell.cp('-rf', overrides, this.www_dir());

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/src/platform.js
----------------------------------------------------------------------
diff --git a/src/platform.js b/src/platform.js
index 7044fb4..a5db481 100644
--- a/src/platform.js
+++ b/src/platform.js
@@ -45,7 +45,7 @@ module.exports = function platform(command, targets, callback) {
         end;
 
     var createOverrides = function(target) {
-        shell.mkdir('-p', path.join(projectRoot, 'merges', target));
+        shell.mkdir('-p', path.join(cordova_util.appDir(projectRoot), 'merges', target));
     };
 
     if (arguments.length === 0) command = 'ls';
@@ -56,7 +56,7 @@ module.exports = function platform(command, targets, callback) {
         });
     }
 
-    var xml = path.join(projectRoot, 'www', 'config.xml');
+    var xml = cordova_util.projectConfig(projectRoot);
     var cfg = new config_parser(xml);
 
     switch(command) {
@@ -125,7 +125,7 @@ module.exports = function platform(command, targets, callback) {
             targets.forEach(function(target) {
                 hooks.fire('before_platform_rm');
                 shell.rm('-rf', path.join(projectRoot, 'platforms', target));
-                shell.rm('-rf', path.join(projectRoot, 'merges', target));
+                shell.rm('-rf', path.join(cordova_util.appDir(projectRoot), 'merges', target));
                 hooks.fire('after_platform_rm');
             });
             break;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/src/plugin.js
----------------------------------------------------------------------
diff --git a/src/plugin.js b/src/plugin.js
index bbe04b3..c2fdc02 100644
--- a/src/plugin.js
+++ b/src/plugin.js
@@ -39,10 +39,8 @@ module.exports = function plugin(command, targets, callback) {
 
     var hooks = new hooker(projectRoot);
 
-    var projectWww = path.join(projectRoot, 'www');
-
     // Grab config info for the project
-    var xml = path.join(projectWww, 'config.xml');
+    var xml = cordova_util.projectConfig(projectRoot);
     var cfg = new config_parser(xml);
     var platforms = cordova_util.listPlatforms(projectRoot);
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/src/prepare.js
----------------------------------------------------------------------
diff --git a/src/prepare.js b/src/prepare.js
index f5164eb..7b30c29 100644
--- a/src/prepare.js
+++ b/src/prepare.js
@@ -44,7 +44,7 @@ module.exports = function prepare(platforms, callback) {
         throw new Error('Current working directory is not a Cordova-based project.');
     }
 
-    var xml = path.join(projectRoot, 'www', 'config.xml');
+    var xml = cordova_util.projectConfig(projectRoot);
     var cfg = new config_parser(xml);
 
     if (arguments.length === 0 || (platforms instanceof Array && platforms.length === 0)) {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/src/serve.js
----------------------------------------------------------------------
diff --git a/src/serve.js b/src/serve.js
index 1967628..771f64f 100644
--- a/src/serve.js
+++ b/src/serve.js
@@ -96,7 +96,7 @@ module.exports.config = function (platform, port, callback) {
         throw new Error('Current working directory is not a Cordova-based project.');
     }
 
-    var xml = path.join(projectRoot, 'www', 'config.xml');
+    var xml = cordova_util.projectConfig(projectRoot);
     var cfg = new config_parser(xml);
 
     // Retrieve the platforms.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/src/util.js
----------------------------------------------------------------------
diff --git a/src/util.js b/src/util.js
index 6bd78da..4620e03 100644
--- a/src/util.js
+++ b/src/util.js
@@ -62,5 +62,14 @@ module.exports = {
         return fs.readdirSync(path.join(project_dir, 'platforms')).filter(function(p) {
             return core_platforms.indexOf(p) > -1;
         });
+    },
+    projectWww: function(projectDir) {
+        return path.join(projectDir, 'app', 'www');
+    },
+    appDir: function(projectDir) {
+        return path.join(projectDir, 'app');
+    },
+    projectConfig: function(projectDir) {
+        return path.join(projectDir, 'app', 'config.xml');
     }
 };

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/config.xml
----------------------------------------------------------------------
diff --git a/templates/app/config.xml b/templates/app/config.xml
new file mode 100644
index 0000000..206bc56
--- /dev/null
+++ b/templates/app/config.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<widget xmlns     = "http://www.w3.org/ns/widgets"
+        xmlns:gap = "http://phonegap.com/ns/1.0"
+        id        = "io.cordova.hello-cordova"
+        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="callback-dev@incubator.apache.org">
+        Apache Cordova Team
+    </author>
+
+    <icon src="res/icon/cordova_512.png"        width="512" height="512" />
+    <icon src="res/icon/cordova_android_96.png" width="96"  height="96"  gap:platform="android" />
+    <icon src="res/icon/cordova_bb_80.png"      width="80"  height="80"  gap:platform="blackberry" />
+    <icon src="res/icon/cordova_ios_144.png"    width="144" height="144" gap:platform="ios" />
+
+    <gap:splash src="res/screen/android_hdpi_landscape.png"      width="800"  height="480"  gap:platform="android" />
+    <gap:splash src="res/screen/android_hdpi_portrait.png"       width="480"  height="800"  gap:platform="android" />
+    <gap:splash src="res/screen/android_ldpi_landscape.png"      width="320"  height="200"  gap:platform="android" />
+    <gap:splash src="res/screen/android_ldpi_portrait.png"       width="200"  height="320"  gap:platform="android" />
+    <gap:splash src="res/screen/android_mdpi_landscape.png"      width="480"  height="320"  gap:platform="android" />
+    <gap:splash src="res/screen/android_mdpi_portrait.png"       width="320"  height="480"  gap:platform="android" />
+    <gap:splash src="res/screen/android_xhdpi_landscape.png"     width="1280" height="720"  gap:platform="android" />
+    <gap:splash src="res/screen/android_xhdpi_portrait.png"      width="720"  height="1280" gap:platform="android" />
+    <gap:splash src="res/screen/blackberry_transparent_300.png"  width="300"  height="300"  gap:platform="blackberry" />
+    <gap:splash src="res/screen/blackberry_transparent_400.png"  width="200"  height="200"  gap:platform="blackberry" />
+    <gap:splash src="res/screen/ipad_landscape.png"              width="1024" height="748"  gap:platform="ios" />
+    <gap:splash src="res/screen/ipad_portrait.png"               width="768"  height="1004" gap:platform="ios" />
+    <gap:splash src="res/screen/ipad_retina_landscape.png"       width="2048" height="1496" gap:platform="ios" />
+    <gap:splash src="res/screen/ipad_retina_portrait.png"        width="1536" height="2008" gap:platform="ios" />
+    <gap:splash src="res/screen/iphone_landscape.png"            width="480"  height="320"  gap:platform="ios" />
+    <gap:splash src="res/screen/iphone_portrait.png"             width="320"  height="480"  gap:platform="ios" />
+    <gap:splash src="res/screen/iphone_retina_landscape.png"     width="960"  height="640"  gap:platform="ios" />
+    <gap:splash src="res/screen/iphone_retina_portrait.png"      width="640"  height="960"  gap:platform="ios" />
+    <gap:splash src="res/screen/windows_phone_portrait.jpg"      width="480"  height="800"  gap:platform="winphone" />
+
+    <feature name="http://api.phonegap.com/1.0/device" />
+
+    <preference name="phonegap-version" value="1.9.0" />
+    <preference name="orientation"      value="default" />
+    <preference name="target-device"    value="universal" />
+    <preference name="fullscreen"       value="false" />
+
+    <access origin="*" />
+</widget>

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/css/index.css
----------------------------------------------------------------------
diff --git a/templates/app/www/css/index.css b/templates/app/www/css/index.css
new file mode 100644
index 0000000..c869f87
--- /dev/null
+++ b/templates/app/www/css/index.css
@@ -0,0 +1,100 @@
+html,
+body {
+    height:100%;
+    font-size:12px;
+    width:100%;
+}
+
+html {
+    display:table;
+}
+
+body {
+    background-color:#A7A7A7;
+    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)
+    );
+    display:table-cell;
+    font-family:'HelveticaNeue-Light', 'HelveticaNeue', Helvetica, Arial, sans-serif;
+    text-transform:uppercase;
+    vertical-align:middle;
+}
+
+.app {
+    background-image:url(../img/cordova.png);
+    background-repeat:no-repeat;
+    margin:0px auto;
+    width:275px;
+}
+
+h1 {
+    font-size:2em;
+    font-weight:300;
+    margin:0px;
+    overflow:visible;
+    padding:0px;
+    text-align:center;
+}
+
+.status {
+    background-color:#333333;
+    border-radius:4px;
+    -webkit-border-radius:4px;
+    color:#FFFFFF;
+    font-size:1em;
+    margin:0px auto;
+    padding:2px 10px;
+    text-align:center;
+    width:100%;
+    max-width:175px;
+}
+
+.status.complete {
+    background-color:#4B946A;
+}
+
+.hide {
+    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;
+}
+
+/* portrait */
+/* @media screen and (max-aspect-ratio: 1/1) */
+.app {
+    background-position:center top;
+    height:100px;              /* adds enough room for text */
+    padding:180px 0px 0px 0px; /* background height - shadow offset */
+}
+
+/* lanscape (when wide enough) */
+@media screen and (min-aspect-ratio: 1/1) and (min-width:445px) {
+    .app {
+        background-position:left center;
+        height:140px;       /* height + padding = background image size */
+        padding-left:170px; /* background width */
+        padding-top:60px;   /* center the text */
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/img/cordova.png
----------------------------------------------------------------------
diff --git a/templates/app/www/img/cordova.png b/templates/app/www/img/cordova.png
new file mode 100644
index 0000000..e8169cf
Binary files /dev/null and b/templates/app/www/img/cordova.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/index.html
----------------------------------------------------------------------
diff --git a/templates/app/www/index.html b/templates/app/www/index.html
new file mode 100644
index 0000000..202af51
--- /dev/null
+++ b/templates/app/www/index.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+        <meta name = "format-detection" content = "telephone=no"/>
+        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width;" />
+        <link rel="stylesheet" type="text/css" href="css/index.css" />
+        <title>Hello Cordova</title>
+    </head>
+    <body>
+        <div class="app">
+            <h1>Apache Cordova</h1>
+            <div id="deviceready">
+                <p class="status pending blink">Connecting to Device</p>
+                <p class="status complete blink hide">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/740ff28d/templates/app/www/js/index.js
----------------------------------------------------------------------
diff --git a/templates/app/www/js/index.js b/templates/app/www/js/index.js
new file mode 100644
index 0000000..6140331
--- /dev/null
+++ b/templates/app/www/js/index.js
@@ -0,0 +1,20 @@
+var app = {
+    initialize: function() {
+        this.bind();
+    },
+    bind: function() {
+        document.addEventListener('deviceready', this.deviceready, false);
+    },
+    deviceready: function() {
+        // note that this is an event handler so the scope is that of the event
+        // so we need to call app.report(), and not this.report()
+        app.report('deviceready');
+    },
+    report: function(id) { 
+        console.log("report:" + id);
+        // hide the .pending <p> and show the .complete <p>
+        document.querySelector('#' + id + ' .pending').className += ' hide';
+        var completeElem = document.querySelector('#' + id + ' .complete');
+        completeElem.className = completeElem.className.split('hide').join('');
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/icon/cordova_128.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/icon/cordova_128.png b/templates/app/www/res/icon/cordova_128.png
new file mode 100644
index 0000000..3516df3
Binary files /dev/null and b/templates/app/www/res/icon/cordova_128.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/icon/cordova_16.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/icon/cordova_16.png b/templates/app/www/res/icon/cordova_16.png
new file mode 100644
index 0000000..54e19c5
Binary files /dev/null and b/templates/app/www/res/icon/cordova_16.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/icon/cordova_24.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/icon/cordova_24.png b/templates/app/www/res/icon/cordova_24.png
new file mode 100644
index 0000000..c7d43ad
Binary files /dev/null and b/templates/app/www/res/icon/cordova_24.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/icon/cordova_256.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/icon/cordova_256.png b/templates/app/www/res/icon/cordova_256.png
new file mode 100644
index 0000000..e1cd0e6
Binary files /dev/null and b/templates/app/www/res/icon/cordova_256.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/icon/cordova_32.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/icon/cordova_32.png b/templates/app/www/res/icon/cordova_32.png
new file mode 100644
index 0000000..734fffc
Binary files /dev/null and b/templates/app/www/res/icon/cordova_32.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/icon/cordova_48.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/icon/cordova_48.png b/templates/app/www/res/icon/cordova_48.png
new file mode 100644
index 0000000..8ad8bac
Binary files /dev/null and b/templates/app/www/res/icon/cordova_48.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/icon/cordova_512.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/icon/cordova_512.png b/templates/app/www/res/icon/cordova_512.png
new file mode 100644
index 0000000..c9465f3
Binary files /dev/null and b/templates/app/www/res/icon/cordova_512.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/icon/cordova_64.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/icon/cordova_64.png b/templates/app/www/res/icon/cordova_64.png
new file mode 100644
index 0000000..03b3849
Binary files /dev/null and b/templates/app/www/res/icon/cordova_64.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/icon/cordova_android_36.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/icon/cordova_android_36.png b/templates/app/www/res/icon/cordova_android_36.png
new file mode 100644
index 0000000..cd5032a
Binary files /dev/null and b/templates/app/www/res/icon/cordova_android_36.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/icon/cordova_android_48.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/icon/cordova_android_48.png b/templates/app/www/res/icon/cordova_android_48.png
new file mode 100644
index 0000000..e79c606
Binary files /dev/null and b/templates/app/www/res/icon/cordova_android_48.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/icon/cordova_android_72.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/icon/cordova_android_72.png b/templates/app/www/res/icon/cordova_android_72.png
new file mode 100644
index 0000000..4d27634
Binary files /dev/null and b/templates/app/www/res/icon/cordova_android_72.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/icon/cordova_android_96.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/icon/cordova_android_96.png b/templates/app/www/res/icon/cordova_android_96.png
new file mode 100644
index 0000000..ec7ffbf
Binary files /dev/null and b/templates/app/www/res/icon/cordova_android_96.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/icon/cordova_bb_80.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/icon/cordova_bb_80.png b/templates/app/www/res/icon/cordova_bb_80.png
new file mode 100644
index 0000000..f86a27a
Binary files /dev/null and b/templates/app/www/res/icon/cordova_bb_80.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/icon/cordova_ios_114.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/icon/cordova_ios_114.png b/templates/app/www/res/icon/cordova_ios_114.png
new file mode 100644
index 0000000..efd9c37
Binary files /dev/null and b/templates/app/www/res/icon/cordova_ios_114.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/icon/cordova_ios_144.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/icon/cordova_ios_144.png b/templates/app/www/res/icon/cordova_ios_144.png
new file mode 100644
index 0000000..dd819da
Binary files /dev/null and b/templates/app/www/res/icon/cordova_ios_144.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/icon/cordova_ios_57.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/icon/cordova_ios_57.png b/templates/app/www/res/icon/cordova_ios_57.png
new file mode 100644
index 0000000..c795fc4
Binary files /dev/null and b/templates/app/www/res/icon/cordova_ios_57.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/icon/cordova_ios_72.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/icon/cordova_ios_72.png b/templates/app/www/res/icon/cordova_ios_72.png
new file mode 100644
index 0000000..b1cfde7
Binary files /dev/null and b/templates/app/www/res/icon/cordova_ios_72.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/android_hdpi_landscape.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/android_hdpi_landscape.png b/templates/app/www/res/screen/android_hdpi_landscape.png
new file mode 100644
index 0000000..a61e2b1
Binary files /dev/null and b/templates/app/www/res/screen/android_hdpi_landscape.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/android_hdpi_portrait.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/android_hdpi_portrait.png b/templates/app/www/res/screen/android_hdpi_portrait.png
new file mode 100644
index 0000000..5d6a28a
Binary files /dev/null and b/templates/app/www/res/screen/android_hdpi_portrait.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/android_ldpi_landscape.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/android_ldpi_landscape.png b/templates/app/www/res/screen/android_ldpi_landscape.png
new file mode 100644
index 0000000..f3934cd
Binary files /dev/null and b/templates/app/www/res/screen/android_ldpi_landscape.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/android_ldpi_portrait.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/android_ldpi_portrait.png b/templates/app/www/res/screen/android_ldpi_portrait.png
new file mode 100644
index 0000000..65ad163
Binary files /dev/null and b/templates/app/www/res/screen/android_ldpi_portrait.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/android_mdpi_landscape.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/android_mdpi_landscape.png b/templates/app/www/res/screen/android_mdpi_landscape.png
new file mode 100644
index 0000000..a1b697c
Binary files /dev/null and b/templates/app/www/res/screen/android_mdpi_landscape.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/android_mdpi_portrait.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/android_mdpi_portrait.png b/templates/app/www/res/screen/android_mdpi_portrait.png
new file mode 100644
index 0000000..ea15693
Binary files /dev/null and b/templates/app/www/res/screen/android_mdpi_portrait.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/android_xhdpi_landscape.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/android_xhdpi_landscape.png b/templates/app/www/res/screen/android_xhdpi_landscape.png
new file mode 100644
index 0000000..79f2f09
Binary files /dev/null and b/templates/app/www/res/screen/android_xhdpi_landscape.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/android_xhdpi_portrait.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/android_xhdpi_portrait.png b/templates/app/www/res/screen/android_xhdpi_portrait.png
new file mode 100644
index 0000000..c2e8042
Binary files /dev/null and b/templates/app/www/res/screen/android_xhdpi_portrait.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/blackberry_transparent_300.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/blackberry_transparent_300.png b/templates/app/www/res/screen/blackberry_transparent_300.png
new file mode 100644
index 0000000..b548bdc
Binary files /dev/null and b/templates/app/www/res/screen/blackberry_transparent_300.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/blackberry_transparent_400.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/blackberry_transparent_400.png b/templates/app/www/res/screen/blackberry_transparent_400.png
new file mode 100644
index 0000000..3facdf9
Binary files /dev/null and b/templates/app/www/res/screen/blackberry_transparent_400.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/ipad_landscape.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/ipad_landscape.png b/templates/app/www/res/screen/ipad_landscape.png
new file mode 100644
index 0000000..04be5ac
Binary files /dev/null and b/templates/app/www/res/screen/ipad_landscape.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/ipad_portrait.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/ipad_portrait.png b/templates/app/www/res/screen/ipad_portrait.png
new file mode 100644
index 0000000..41e839d
Binary files /dev/null and b/templates/app/www/res/screen/ipad_portrait.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/ipad_retina_landscape.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/ipad_retina_landscape.png b/templates/app/www/res/screen/ipad_retina_landscape.png
new file mode 100644
index 0000000..95c542d
Binary files /dev/null and b/templates/app/www/res/screen/ipad_retina_landscape.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/ipad_retina_portrait.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/ipad_retina_portrait.png b/templates/app/www/res/screen/ipad_retina_portrait.png
new file mode 100644
index 0000000..aae1862
Binary files /dev/null and b/templates/app/www/res/screen/ipad_retina_portrait.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/iphone_landscape.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/iphone_landscape.png b/templates/app/www/res/screen/iphone_landscape.png
new file mode 100644
index 0000000..d154883
Binary files /dev/null and b/templates/app/www/res/screen/iphone_landscape.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/iphone_portrait.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/iphone_portrait.png b/templates/app/www/res/screen/iphone_portrait.png
new file mode 100644
index 0000000..6fcba56
Binary files /dev/null and b/templates/app/www/res/screen/iphone_portrait.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/iphone_retina_landscape.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/iphone_retina_landscape.png b/templates/app/www/res/screen/iphone_retina_landscape.png
new file mode 100644
index 0000000..0165669
Binary files /dev/null and b/templates/app/www/res/screen/iphone_retina_landscape.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/iphone_retina_portrait.png
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/iphone_retina_portrait.png b/templates/app/www/res/screen/iphone_retina_portrait.png
new file mode 100644
index 0000000..bd24886
Binary files /dev/null and b/templates/app/www/res/screen/iphone_retina_portrait.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/res/screen/windows_phone_portrait.jpg
----------------------------------------------------------------------
diff --git a/templates/app/www/res/screen/windows_phone_portrait.jpg b/templates/app/www/res/screen/windows_phone_portrait.jpg
new file mode 100644
index 0000000..9f95387
Binary files /dev/null and b/templates/app/www/res/screen/windows_phone_portrait.jpg differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/spec.html
----------------------------------------------------------------------
diff --git a/templates/app/www/spec.html b/templates/app/www/spec.html
new file mode 100644
index 0000000..83d7d2e
--- /dev/null
+++ b/templates/app/www/spec.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<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/740ff28d/templates/app/www/spec/helper.js
----------------------------------------------------------------------
diff --git a/templates/app/www/spec/helper.js b/templates/app/www/spec/helper.js
new file mode 100644
index 0000000..9f99445
--- /dev/null
+++ b/templates/app/www/spec/helper.js
@@ -0,0 +1,11 @@
+afterEach(function() {
+    document.getElementById('stage').innerHTML = '';
+});
+
+var helper = {
+    trigger: function(obj, name) {
+        var e = document.createEvent('Event');
+        e.initEvent(name, true, true);
+        obj.dispatchEvent(e);
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/740ff28d/templates/app/www/spec/index.js
----------------------------------------------------------------------
diff --git a/templates/app/www/spec/index.js b/templates/app/www/spec/index.js
new file mode 100644
index 0000000..121cf63
--- /dev/null
+++ b/templates/app/www/spec/index.js
@@ -0,0 +1,49 @@
+describe('app', function() {
+    describe('initialize', function() {
+        it('should bind deviceready', function() {
+            runs(function() {
+                spyOn(app, 'deviceready');
+                app.initialize();
+                helper.trigger(window.document, 'deviceready');
+            });
+
+            waitsFor(function() {
+                return (app.deviceready.calls.length > 0);
+            }, 'deviceready should be called once', 500);
+
+            runs(function() {
+                expect(app.deviceready).toHaveBeenCalled();
+            });
+        });
+    });
+
+    describe('deviceready', function() {
+        it('should report that it fired', function() {
+            spyOn(app, 'report');
+            app.deviceready();
+            expect(app.report).toHaveBeenCalledWith('deviceready');
+        });
+    });
+
+    describe('report', function() {
+        beforeEach(function() {
+            var el = document.getElementById('stage');
+            el.innerHTML = ['<div id="deviceready">',
+                            '    <p class="status pending">Pending</p>',
+                            '    <p class="status complete hide">Complete</p>',
+                            '</div>'].join('\n');
+        });
+
+        it('should show the completion state', function() {
+            app.report('deviceready');
+            var el = document.querySelector('#deviceready .complete:not(.hide)');
+            expect(el).toBeTruthy();
+        });
+
+        it('should hide the pending state', function() {
+            app.report('deviceready');
+            var el = document.querySelector('#deviceready .pending.hide');
+            expect(el).toBeTruthy();
+        });
+    });
+});

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


[15/43] git commit: using plugman as a lib and updating package.json to use npm version

Posted by an...@apache.org.
using plugman as a lib and updating package.json to use npm version


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

Branch: refs/heads/master
Commit: 655776cf50cb9103a25aa2cb71b4b07cff0a34bb
Parents: b6be347
Author: Anis Kadri <an...@apache.org>
Authored: Thu May 2 19:14:22 2013 -0700
Committer: Anis Kadri <an...@apache.org>
Committed: Thu May 2 19:14:22 2013 -0700

----------------------------------------------------------------------
 package.json  |    2 +-
 src/plugin.js |   31 +++++++++----------------------
 2 files changed, 10 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/655776cf/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index d7bfb17..fc7f0b4 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,7 @@
   "dependencies": {
     "colors":">=0.6.0",
     "elementtree":"0.1.3",
-    "plugman":"git+https://github.com/imhotep/plugman.git#0.5.7",
+    "plugman":"0.6.1",
     "plist":"git+https://github.com/filmaj/node-plist.git",
     "xcode":"0.5.1",
     "express":"3.0",

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/655776cf/src/plugin.js
----------------------------------------------------------------------
diff --git a/src/plugin.js b/src/plugin.js
index 55ccf48..9f3138d 100644
--- a/src/plugin.js
+++ b/src/plugin.js
@@ -27,7 +27,8 @@ var cordova_util  = require('./util'),
     core_platforms= require('../platforms'),
     platform      = require('./platform'),
     plugin_parser = require('./plugin_parser'),
-    ls            = fs.readdirSync;
+    ls            = fs.readdirSync,
+    plugman       = require('plugman');
 
 module.exports = function plugin(command, targets, callback) {
     var projectRoot = cordova_util.isCordova(process.cwd());
@@ -73,7 +74,6 @@ module.exports = function plugin(command, targets, callback) {
         case 'add':
             targets.forEach(function(target, index) {
                 hooks.fire('before_plugin_add');
-                var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'main.js');
                 var pluginsDir = path.join(projectRoot, 'plugins');
 
                 if (target[target.length - 1] == path.sep) {
@@ -81,17 +81,13 @@ module.exports = function plugin(command, targets, callback) {
                 }
 
                 // Fetch the plugin first.
-                var cmd = util.format('%s --fetch --plugin "%s" --plugins_dir "%s"', cli, target, pluginsDir);
-                console.log(cmd);
-                var plugin_fetch = shell.exec(cmd, {silent: true});
-                if (plugin_fetch.code > 0) throw new Error('An error occured during plugin fetching:\n' + plugin_fetch.output);
-
+                plugman.fetch(target, pluginsDir, false);
+                
                 // Iterate over all platforms in the project and install the plugin.
+                // TODO add cli_variables if it's important (last argument) ?
                 platforms.forEach(function(platform) {
-                    cmd = util.format('%s --platform %s --project "%s" --plugin "%s" --plugins_dir "%s"', cli, platform, path.join(projectRoot, 'platforms', platform), names[index], pluginsDir);
-                    console.log(cmd);
-                    var plugin_cli = shell.exec(cmd, {silent:true});
-                    if (plugin_cli.code > 0) throw new Error('An error occured during plugin installation for ' + platform + ': ' + plugin_cli.output);
+                    plugman.install(platform, path.join(projectRoot, 'platforms', platform), 
+                                    names[index], pluginsDir, {});
                 });
 
                 hooks.fire('after_plugin_add');
@@ -109,8 +105,6 @@ module.exports = function plugin(command, targets, callback) {
                 if (plugins.indexOf(targetName) > -1) {
                     var targetPath = path.join(pluginPath, targetName);
                     hooks.fire('before_plugin_rm');
-                    var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'plugman.js');
-
                     // Check if there is at least one match between plugin
                     // supported platforms and app platforms
                     var pluginXml = new plugin_parser(path.join(targetPath, 'plugin.xml'));
@@ -123,19 +117,12 @@ module.exports = function plugin(command, targets, callback) {
                     // and the app, and uninstall.
                     // If this is a web-only plugin with no platform tags, this step
                     // is not needed and we just --remove the plugin below.
-                    var cmd;
                     intersection.forEach(function(platform) {
-                        cmd = util.format('%s --platform %s --project "%s" --plugin "%s" --plugins_dir "%s" --uninstall', cli, platform, path.join(projectRoot, 'platforms', platform), targetName, path.join(projectRoot, 'plugins'));
-                        console.log(cmd);
-                        var plugin_cli = shell.exec(cmd, {silent:true});
-                        if (plugin_cli.code > 0) throw new Error('An error occured during plugin uninstallation for ' + platform + '. ' + plugin_cli.output);
+                        plugman.uninstall(platform, path.join(projectRoot, 'platforms', platform), targetName, path.join(projectRoot, 'plugins'));
                     });
 
                     // Finally remove the plugin dir from plugins/
-                    cmd = util.format('%s --plugin "%s" --plugins_dir "%s" --remove', cli, targetName, path.join(projectRoot, 'plugins'));
-                    console.log(cmd);
-                    var plugin_remove = shell.exec(cmd, {silent: true});
-                    if (plugin_remove.code > 0) throw new Error('An error occurred during plugin removal:\n' + plugin_remove.output);
+                    plugman.remove(targetName, path.join(projectRoot, 'plugins'));
 
                     hooks.fire('after_plugin_rm');
                 } else {


[24/43] git commit: 2.6.0rc1 used for libs now. Bumped npm version to 2.6.0. added androids local.properties to gitignore.

Posted by an...@apache.org.
2.6.0rc1 used for libs now. Bumped npm version to 2.6.0. added androids local.properties to gitignore.


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

Branch: refs/heads/master
Commit: 1ed1ee2d7ee5e2ec05c14d21747e8a5fdbf98a76
Parents: 6ad6a26
Author: Fil Maj <ma...@gmail.com>
Authored: Mon Mar 25 14:52:11 2013 -0700
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu May 9 14:26:05 2013 -0700

----------------------------------------------------------------------
 .gitignore                                         |    2 +-
 lib/cordova-android/VERSION                        |    2 +-
 lib/cordova-android/bin/create                     |   16 +-
 .../bin/templates/cordova/appinfo.jar              |  Bin 1574 -> 1574 bytes
 .../bin/templates/project/assets/www/index.html    |    2 +-
 lib/cordova-android/bin/update                     |  139 ++++
 lib/cordova-android/bin/update.bat                 |   32 +
 lib/cordova-android/bin/update.js                  |  193 ++++++
 .../framework/assets/js/cordova.android.js         |  474 +++++++++++---
 .../framework/assets/www/index.html                |    2 +-
 .../src/org/apache/cordova/AudioHandler.java       |    6 +-
 .../src/org/apache/cordova/AudioPlayer.java        |   15 +-
 .../src/org/apache/cordova/CameraLauncher.java     |   16 +-
 .../framework/src/org/apache/cordova/Capture.java  |   14 +-
 .../framework/src/org/apache/cordova/Config.java   |   10 +
 .../src/org/apache/cordova/CordovaArgs.java        |    5 +-
 .../org/apache/cordova/CordovaChromeClient.java    |    2 +-
 .../src/org/apache/cordova/CordovaWebView.java     |  124 +---
 .../org/apache/cordova/CordovaWebViewClient.java   |  103 ++--
 .../framework/src/org/apache/cordova/Device.java   |    2 +-
 .../framework/src/org/apache/cordova/DroidGap.java |   13 +-
 .../src/org/apache/cordova/FileHelper.java         |  142 ++++
 .../src/org/apache/cordova/FileTransfer.java       |   81 ++-
 .../src/org/apache/cordova/FileUtils.java          |  350 ++++-------
 .../src/org/apache/cordova/GeoBroker.java          |    2 +-
 .../cordova/IceCreamCordovaWebViewClient.java      |   16 +-
 .../src/org/apache/cordova/InAppBrowser.java       |  135 ++++-
 .../src/org/apache/cordova/JSONUtils.java          |   24 +
 .../org/apache/cordova/NativeToJsMessageQueue.java |   13 +-
 .../src/org/apache/cordova/Notification.java       |  167 ++++-
 .../org/apache/cordova/api/CallbackContext.java    |    9 +
 .../src/org/apache/cordova/api/CordovaPlugin.java  |   18 +-
 .../src/org/apache/cordova/api/PluginManager.java  |   23 +-
 .../src/org/apache/cordova/api/PluginResult.java   |   11 +-
 lib/cordova-blackberry/bin/create                  |   21 +-
 .../bin/templates/project/www/index.html           |    4 +-
 .../ext/src/org/apache/cordova/util/FileUtils.java |   33 +-
 .../javascript/cordova.blackberry.js               |  365 +++++++++--
 .../CordovaLib/Classes/CDVAvailability.h           |   19 +-
 lib/cordova-ios/CordovaLib/Classes/CDVCamera.h     |    4 +-
 lib/cordova-ios/CordovaLib/Classes/CDVCamera.m     |   53 ++
 lib/cordova-ios/CordovaLib/Classes/CDVCapture.m    |   10 +-
 .../CordovaLib/Classes/CDVCommandDelegate.h        |    1 -
 .../CordovaLib/Classes/CDVCommandDelegateImpl.m    |   22 +-
 .../CordovaLib/Classes/CDVCommandQueue.h           |    8 +-
 .../CordovaLib/Classes/CDVCommandQueue.m           |   17 +-
 .../CordovaLib/Classes/CDVConfigParser.m           |    2 +-
 lib/cordova-ios/CordovaLib/Classes/CDVConnection.m |   12 +-
 lib/cordova-ios/CordovaLib/Classes/CDVContact.m    |   32 +-
 lib/cordova-ios/CordovaLib/Classes/CDVContacts.h   |   14 +-
 lib/cordova-ios/CordovaLib/Classes/CDVContacts.m   |  490 +++++++-------
 lib/cordova-ios/CordovaLib/Classes/CDVEcho.m       |    7 +
 lib/cordova-ios/CordovaLib/Classes/CDVExif.h       |   43 ++
 lib/cordova-ios/CordovaLib/Classes/CDVFile.h       |    2 +
 lib/cordova-ios/CordovaLib/Classes/CDVFile.m       |  285 +++++----
 .../CordovaLib/Classes/CDVFileTransfer.h           |    8 +-
 .../CordovaLib/Classes/CDVFileTransfer.m           |   51 +-
 .../CordovaLib/Classes/CDVGlobalization.m          |   62 +-
 .../CordovaLib/Classes/CDVInAppBrowser.h           |    3 +
 .../CordovaLib/Classes/CDVInAppBrowser.m           |   41 +-
 .../CordovaLib/Classes/CDVInvokedUrlCommand.h      |    6 +-
 .../CordovaLib/Classes/CDVJpegHeaderWriter.h       |   60 ++
 .../CordovaLib/Classes/CDVJpegHeaderWriter.m       |  472 +++++++++++++
 .../CordovaLib/Classes/CDVLocalStorage.h           |    4 +-
 .../CordovaLib/Classes/CDVLocalStorage.m           |   36 +-
 lib/cordova-ios/CordovaLib/Classes/CDVLocation.h   |    8 +-
 lib/cordova-ios/CordovaLib/Classes/CDVLocation.m   |   24 +-
 .../CordovaLib/Classes/CDVNotification.h           |    1 +
 .../CordovaLib/Classes/CDVNotification.m           |   89 ++-
 lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h     |    8 +-
 lib/cordova-ios/CordovaLib/Classes/CDVPlugin.m     |    9 +-
 .../CordovaLib/Classes/CDVPluginResult.h           |    7 +
 .../CordovaLib/Classes/CDVPluginResult.m           |   57 ++-
 .../CordovaLib/Classes/CDVReachability.m           |   28 +-
 lib/cordova-ios/CordovaLib/Classes/CDVSound.m      |   21 +-
 .../CordovaLib/Classes/CDVSplashScreen.h           |    3 +-
 .../CordovaLib/Classes/CDVSplashScreen.m           |  176 +++--
 .../CordovaLib/Classes/CDVURLProtocol.m            |   12 +-
 .../CordovaLib/Classes/CDVUserAgentUtil.m          |    2 +-
 .../CordovaLib/Classes/CDVViewController.h         |   10 +-
 .../CordovaLib/Classes/CDVViewController.m         |  140 ++++-
 .../CordovaLib/Classes/CDVWebViewDelegate.m        |   30 +-
 lib/cordova-ios/CordovaLib/Classes/NSData+Base64.m |   19 +-
 .../CordovaLib/Classes/NSDictionary+Extensions.m   |    2 +-
 .../CordovaLib.xcodeproj/project.pbxproj           |   14 +
 lib/cordova-ios/CordovaLib/VERSION                 |    2 +-
 lib/cordova-ios/CordovaLib/cordova.ios.js          |  521 ++++++++++++---
 .../CordovaLibTests/CDVFakeFileManager.h           |    2 +-
 .../CordovaLibTests/CDVFileTransferTests.m         |   12 +-
 .../CordovaLibTests/CDVLocalStorageTests.m         |   24 +-
 lib/cordova-ios/CordovaLibTests/CDVUserAgentTest.m |    4 +-
 lib/cordova-ios/CordovaLibTests/CDVWebViewTest.m   |    4 +-
 .../CordovaLibTests/CordovaLibApp/config.xml       |    6 +-
 .../CordovaTests.xcodeproj/project.pbxproj         |    6 +
 lib/cordova-ios/CordovaLibTests/ExifTests.h        |   27 +
 lib/cordova-ios/CordovaLibTests/ExifTests.m        |  155 +++++
 lib/cordova-ios/RELEASENOTES.md                    |   66 ++-
 .../project/__TESTING__.xcodeproj/project.pbxproj  |    6 +-
 .../project/__TESTING__/Classes/AppDelegate.m      |   18 +-
 .../Resources/splash/Default-568h@2x~iphone.png    |  Bin 29944 -> 34225 bytes
 .../Resources/splash/Default-Landscape@2x~ipad.png |  Bin 75573 -> 77300 bytes
 .../Resources/splash/Default-Landscape~ipad.png    |  Bin 33147 -> 34935 bytes
 .../Resources/splash/Default-Portrait@2x~ipad.png  |  Bin 74097 -> 76546 bytes
 .../Resources/splash/Default-Portrait~ipad.png     |  Bin 32666 -> 34278 bytes
 .../bin/templates/project/__TESTING__/config.xml   |   20 +-
 .../bin/templates/project/www/index.html           |    2 +-
 .../guides/Cordova Plugin Upgrade Guide.md         |    6 +
 lib/cordova-ios/hooks/pre-commit                   |    6 +
 package.json                                       |    2 +-
 109 files changed, 4423 insertions(+), 1476 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 3abe651..b31c8bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,8 +6,8 @@ spec/fixtures/projects/native
 spec/fixtures/projects/cordova
 lib/cordova-android/framework/bin
 lib/cordova-android/framework/gen
+lib/cordova-android/framework/local.properties
 .idea/*
 spec/fixtures/*
 .gitcore
 *.jar
-lib/*

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-android/VERSION b/lib/cordova-android/VERSION
index 437459c..f47de85 100644
--- a/lib/cordova-android/VERSION
+++ b/lib/cordova-android/VERSION
@@ -1 +1 @@
-2.5.0
+2.6.0rc1

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/bin/create
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/create b/lib/cordova-android/bin/create
index ea214ac..2eae82b 100755
--- a/lib/cordova-android/bin/create
+++ b/lib/cordova-android/bin/create
@@ -59,10 +59,10 @@ function on_exit {
 }
 
 function createAppInfoJar {
-    (cd "$BUILD_PATH"/bin/templates/cordova/ApplicationInfo &&
-     javac ApplicationInfo.java &&
-     jar -cfe ../appinfo.jar ApplicationInfo ApplicationInfo.class
-    )
+    pushd "$BUILD_PATH"/bin/templates/cordova/ApplicationInfo > /dev/null
+    javac ApplicationInfo.java
+    jar -cfe ../appinfo.jar ApplicationInfo ApplicationInfo.class
+    popd > /dev/null
 }
 
 function on_error {
@@ -108,7 +108,7 @@ fi
 # if this a distribution release no need to build a jar
 if [ ! -e "$BUILD_PATH"/cordova-$VERSION.jar ] && [ -d "$BUILD_PATH"/framework ]
 then
-# update the cordova-android framework for the desired target
+    # update the cordova-android framework for the desired target
     "$ANDROID_BIN" update project --target $TARGET --path "$BUILD_PATH"/framework &> /dev/null
 
     if [ ! -e "$BUILD_PATH"/framework/libs/commons-codec-1.7.jar ]; then
@@ -121,8 +121,10 @@ then
         rm commons-codec-1.7-bin.zip && rm -rf commons-codec-1.7
     fi
 
-# compile cordova.js and cordova.jar
-    (cd "$BUILD_PATH"/framework && ant jar &> /dev/null )
+    # compile cordova.js and cordova.jar
+    pushd "$BUILD_PATH"/framework > /dev/null
+    ant jar > /dev/null
+    popd > /dev/null
 fi
 
 # create new android project

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/bin/templates/cordova/appinfo.jar
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/cordova/appinfo.jar b/lib/cordova-android/bin/templates/cordova/appinfo.jar
index fff4d0f..7f8ac60 100644
Binary files a/lib/cordova-android/bin/templates/cordova/appinfo.jar and b/lib/cordova-android/bin/templates/cordova/appinfo.jar differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/bin/templates/project/assets/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/templates/project/assets/www/index.html b/lib/cordova-android/bin/templates/project/assets/www/index.html
index b8c0535..5596f62 100644
--- a/lib/cordova-android/bin/templates/project/assets/www/index.html
+++ b/lib/cordova-android/bin/templates/project/assets/www/index.html
@@ -33,7 +33,7 @@
                 <p class="event received">Device is Ready</p>
             </div>
         </div>
-        <script type="text/javascript" src="cordova-2.5.0.js"></script>
+        <script type="text/javascript" src="cordova-2.6.0rc1.js"></script>
         <script type="text/javascript" src="js/index.js"></script>
         <script type="text/javascript">
             app.initialize();

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/bin/update
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/update b/lib/cordova-android/bin/update
new file mode 100755
index 0000000..0e86886
--- /dev/null
+++ b/lib/cordova-android/bin/update
@@ -0,0 +1,139 @@
+#! /bin/bash
+#       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.
+#
+# update a cordova/android project's command line tools
+# 
+# USAGE
+#   ./update [path]
+#
+
+set -e
+
+if [ -z "$1" ] || [ "$1" == "-h" ]
+then
+    echo 'usage: update path'
+    echo "Make sure the Android SDK tools folder is in your PATH!"
+    exit 0
+fi
+
+BUILD_PATH="$( cd "$( dirname "$0" )/.." && pwd )"
+VERSION=$(cat "$BUILD_PATH"/VERSION)
+
+PROJECT_PATH="${1:-'./example'}"
+
+if [ ! -d "$PROJECT_PATH" ]
+then
+    echo "The project path has to exist for it to be updated"
+    exit 0
+fi
+
+
+# cleanup after exit and/or on error
+function on_exit {
+    if [ -f "$BUILD_PATH"/framework/assets/www/cordova-$VERSION.js ]
+    then
+        rm "$BUILD_PATH"/framework/assets/www/cordova-$VERSION.js
+    fi
+    if [ -f "$BUILD_PATH"/framework/cordova-$VERSION.jar ]
+    then
+        rm "$BUILD_PATH"/framework/cordova-$VERSION.jar
+    fi
+}
+
+function createAppInfoJar {
+    (cd "$BUILD_PATH"/bin/templates/cordova/ApplicationInfo &&
+     javac ApplicationInfo.java &&
+     jar -cfe ../appinfo.jar ApplicationInfo ApplicationInfo.class
+    )
+}
+
+function on_error {
+    echo "An unexpected error occurred: $previous_command exited with $?"
+    echo "Deleting project..."
+    [ -d "$PROJECT_PATH" ] && rm -rf "$PROJECT_PATH"
+    exit 1
+}
+
+function replace {
+    local pattern=$1
+    local filename=$2
+    # Mac OS X requires -i argument
+    if [[ "$OSTYPE" =~ "darwin" ]]
+    then
+        /usr/bin/sed -i '' -e $pattern "$filename"
+    elif [[ "$OSTYPE" =~ "linux" ]]
+    then
+        /bin/sed -i -e $pattern "$filename"
+    fi
+}
+
+# we do not want the script to silently fail
+trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG
+trap on_error ERR
+trap on_exit EXIT
+
+ANDROID_BIN="${ANDROID_BIN:=$( which android )}"
+
+TARGET=$("$ANDROID_BIN" list targets | grep id: | tail -1 | cut -f 2 -d ' ' )
+API_LEVEL=$("$ANDROID_BIN" list target | grep "API level:" | tail -n 1 | cut -f 2 -d ':' | tr -d ' ')
+
+# check that build targets exist
+if [ -z "$TARGET" ] || [ -z "$API_LEVEL" ]
+then
+    echo "No Android Targets are installed. Please install at least one via the android SDK"
+    exit 1
+fi
+
+# if this a distribution release no need to build a jar
+if [ ! -e "$BUILD_PATH"/cordova-$VERSION.jar ] && [ -d "$BUILD_PATH"/framework ]
+then
+# update the cordova-android framework for the desired target
+    "$ANDROID_BIN" update project --target $TARGET --path "$BUILD_PATH"/framework &> /dev/null
+
+    if [ ! -e "$BUILD_PATH"/framework/libs/commons-codec-1.7.jar ]; then
+        # Use curl to get the jar (TODO: Support Apache Mirrors)
+        curl -OL http://archive.apache.org/dist/commons/codec/binaries/commons-codec-1.7-bin.zip &> /dev/null
+        unzip commons-codec-1.7-bin.zip &> /dev/null
+        mkdir -p "$BUILD_PATH"/framework/libs
+        cp commons-codec-1.7/commons-codec-1.7.jar "$BUILD_PATH"/framework/libs
+        # cleanup yo
+        rm commons-codec-1.7-bin.zip && rm -rf commons-codec-1.7
+    fi
+
+# compile cordova.js and cordova.jar
+    (cd "$BUILD_PATH"/framework && ant jar &> /dev/null )
+fi
+
+# copy cordova.js, cordova.jar and res/xml
+if [ -d "$BUILD_PATH"/framework ]
+then
+    cp "$BUILD_PATH"/framework/assets/www/cordova-$VERSION.js "$PROJECT_PATH"/assets/www/cordova-$VERSION.js
+    cp "$BUILD_PATH"/framework/cordova-$VERSION.jar "$PROJECT_PATH"/libs/cordova-$VERSION.jar
+else
+    cp "$BUILD_PATH"/cordova-$VERSION.js "$PROJECT_PATH"/assets/www/cordova-$VERSION.js
+    cp "$BUILD_PATH"/cordova-$VERSION.jar "$PROJECT_PATH"/libs/cordova-$VERSION.jar
+fi
+
+# creating cordova folder and copying run/build/log/launch scripts
+cp "$BUILD_PATH"/bin/templates/cordova/appinfo.jar "$PROJECT_PATH"/cordova/appinfo.jar
+cp "$BUILD_PATH"/bin/templates/cordova/cordova "$PROJECT_PATH"/cordova/cordova
+cp "$BUILD_PATH"/bin/templates/cordova/build "$PROJECT_PATH"/cordova/build
+cp "$BUILD_PATH"/bin/templates/cordova/release "$PROJECT_PATH"/cordova/release
+cp "$BUILD_PATH"/bin/templates/cordova/clean "$PROJECT_PATH"/cordova/clean
+cp "$BUILD_PATH"/bin/templates/cordova/log "$PROJECT_PATH"/cordova/log
+cp "$BUILD_PATH"/bin/templates/cordova/run "$PROJECT_PATH"/cordova/run

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/bin/update.bat
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/update.bat b/lib/cordova-android/bin/update.bat
new file mode 100644
index 0000000..a61fd26
--- /dev/null
+++ b/lib/cordova-android/bin/update.bat
@@ -0,0 +1,32 @@
+:: Licensed to the Apache Software Foundation (ASF) under one
+:: or more contributor license agreements.  See the NOTICE file
+:: distributed with this work for additional information
+:: regarding copyright ownership.  The ASF licenses this file
+:: to you under the Apache License, Version 2.0 (the
+:: "License"); you may not use this file except in compliance
+:: with the License.  You may obtain a copy of the License at
+:: 
+:: http://www.apache.org/licenses/LICENSE-2.0
+:: 
+:: Unless required by applicable law or agreed to in writing,
+:: software distributed under the License is distributed on an
+:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+:: KIND, either express or implied.  See the License for the
+:: specific language governing permissions and limitations
+:: under the License.
+
+@ECHO OFF
+IF NOT DEFINED JAVA_HOME GOTO MISSING
+FOR %%X in (java.exe javac.exe ant.bat android.bat) do (
+    SET FOUND=%%~$PATH:X
+    IF NOT DEFINED FOUND GOTO MISSING
+)
+cscript "%~dp0\update.js" %*
+GOTO END
+:MISSING
+ECHO Missing one of the following:
+ECHO JDK: http://java.oracle.com
+ECHO Android SDK: http://developer.android.com
+ECHO Apache ant: http://ant.apache.org
+EXIT /B 1
+:END

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/bin/update.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/bin/update.js b/lib/cordova-android/bin/update.js
new file mode 100644
index 0000000..244dcc1
--- /dev/null
+++ b/lib/cordova-android/bin/update.js
@@ -0,0 +1,193 @@
+/*
+       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.
+*/
+
+/*
+ * create a cordova/android project
+ *
+ * USAGE
+ *  ./update [path]
+ */
+
+var fso = WScript.CreateObject('Scripting.FileSystemObject');
+
+function read(filename) {
+    var fso=WScript.CreateObject("Scripting.FileSystemObject");
+    var f=fso.OpenTextFile(filename, 1);
+    var s=f.ReadAll();
+    f.Close();
+    return s;
+}
+
+function checkTargets(targets) {
+    if(!targets) {
+        WScript.Echo("You do not have any android targets setup. Please create at least one target with the `android` command");
+        WScript.Quit(69);
+    }
+}
+
+function setTarget() {
+    var targets = shell.Exec('android.bat list targets').StdOut.ReadAll().match(/id:\s\d+/g);
+    checkTargets(targets);
+    return targets[targets.length - 1].replace(/id: /, ""); // TODO: give users the option to set their target 
+}
+
+function setApiLevel() {
+    var targets = shell.Exec('android.bat list targets').StdOut.ReadAll().match(/API level:\s\d+/g);
+    checkTargets(targets);
+    return targets[targets.length - 1].replace(/API level: /, "");
+}
+
+function write(filename, contents) {
+    var fso=WScript.CreateObject("Scripting.FileSystemObject");
+    var f=fso.OpenTextFile(filename, 2, true);
+    f.Write(contents);
+    f.Close();
+}
+
+function replaceInFile(filename, regexp, replacement) {
+    write(filename, read(filename).replace(regexp, replacement));
+}
+
+function exec(command) {
+    var oShell=shell.Exec(command);
+    while (oShell.Status == 0) {
+        if(!oShell.StdOut.AtEndOfStream) {
+            var line = oShell.StdOut.ReadLine();
+            // XXX: Change to verbose mode 
+            // WScript.StdOut.WriteLine(line);
+        }
+        WScript.sleep(100);
+    }
+}
+
+function createAppInfoJar() {
+    if(!fso.FileExists(ROOT+"\\bin\\templates\\cordova\\appinfo.jar")) {
+        WScript.Echo("Creating appinfo.jar...");
+        var cur = shell.CurrentDirectory;
+        shell.CurrentDirectory = ROOT+"\\bin\\templates\\cordova\\ApplicationInfo";
+        exec("javac ApplicationInfo.java");
+        exec("jar -cfe ..\\appinfo.jar ApplicationInfo ApplicationInfo.class");
+        shell.CurrentDirectory = cur;
+    }
+}
+
+function cleanup() {
+    if(fso.FileExists(ROOT + '\\framework\\cordova-'+VERSION+'.jar')) {
+        fso.DeleteFile(ROOT + '\\framework\\cordova-'+VERSION+'.jar');
+    }
+    if(fso.FileExists(ROOT + '\\framework\\assets\\www\\cordova-'+VERSION+'.js')) {
+        fso.DeleteFile(ROOT + '\\framework\\assets\\www\\cordova-'+VERSION+'.js');
+    }
+}
+
+function downloadCommonsCodec() {
+    if (!fso.FileExists(ROOT + '\\framework\\libs\\commons-codec-1.7.jar')) {
+      // We need the .jar
+      var url = 'http://archive.apache.org/dist/commons/codec/binaries/commons-codec-1.7-bin.zip';
+      var libsPath = ROOT + '\\framework\\libs';
+      var savePath = libsPath + '\\commons-codec-1.7-bin.zip';
+      if (!fso.FileExists(savePath)) {
+        if(!fso.FolderExists(ROOT + '\\framework\\libs')) {
+            fso.CreateFolder(libsPath);
+        }
+        // We need the zip to get the jar
+        var xhr = WScript.CreateObject('MSXML2.XMLHTTP');
+        xhr.open('GET', url, false);
+        xhr.send();
+        if (xhr.status == 200) {
+          var stream = WScript.CreateObject('ADODB.Stream');
+          stream.Open();
+          stream.Type = 1;
+          stream.Write(xhr.ResponseBody);
+          stream.Position = 0;
+          stream.SaveToFile(savePath);
+          stream.Close();
+        } else {
+          WScript.Echo('Could not retrieve the commons-codec. Please download it yourself and put into the framework/libs directory. This process may fail now. Sorry.');
+        }
+      }
+      var app = WScript.CreateObject('Shell.Application');
+      var source = app.NameSpace(savePath).Items();
+      var target = app.NameSpace(ROOT + '\\framework\\libs');
+      target.CopyHere(source, 256);
+      
+      // Move the jar into libs
+      fso.MoveFile(ROOT + '\\framework\\libs\\commons-codec-1.7\\commons-codec-1.7.jar', ROOT + '\\framework\\libs\\commons-codec-1.7.jar');
+      
+      // Clean up
+      fso.DeleteFile(ROOT + '\\framework\\libs\\commons-codec-1.7-bin.zip');
+      fso.DeleteFolder(ROOT + '\\framework\\libs\\commons-codec-1.7', true);
+    }
+}
+
+var args = WScript.Arguments, PROJECT_PATH="example", 
+    shell=WScript.CreateObject("WScript.Shell");
+    
+// working dir
+var ROOT = WScript.ScriptFullName.split('\\bin\\update.js').join('');
+
+if (args.Count() == 1) {
+    PROJECT_PATH=args(0);
+}
+
+if(!fso.FolderExists(PROJECT_PATH)) {
+    WScript.Echo("Project doesn't exist!");
+    WScript.Quit(1);
+}
+
+var TARGET=setTarget();
+var API_LEVEL=setApiLevel();
+var VERSION=read(ROOT+'\\VERSION').replace(/\r\n/,'').replace(/\n/,'');
+
+// build from source. distro should have these files
+if (!fso.FileExists(ROOT+'\\cordova-'+VERSION+'.jar') &&
+    !fso.FileExists(ROOT+'\\cordova-'+VERSION+'.js')) {
+    WScript.Echo("Building jar and js files...");
+    // update the cordova framework project to a target that exists on this machine
+    exec('android.bat update project --target '+TARGET+' --path '+ROOT+'\\framework');
+    // pull down commons codec if necessary
+    downloadCommonsCodec();
+    exec('ant.bat -f \"'+ ROOT +'\\framework\\build.xml\" jar');
+}
+
+// check if we have the source or the distro files
+WScript.Echo("Copying js, jar & config.xml files...");
+if(fso.FolderExists(ROOT + '\\framework')) {
+    exec('%comspec% /c copy "'+ROOT+'"\\framework\\assets\\www\\cordova-'+VERSION+'.js '+PROJECT_PATH+'\\assets\\www\\cordova-'+VERSION+'.js /Y');
+    exec('%comspec% /c copy "'+ROOT+'"\\framework\\cordova-'+VERSION+'.jar '+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar /Y');
+} else {
+    // copy in cordova.js
+    exec('%comspec% /c copy "'+ROOT+'"\\cordova-'+VERSION+'.js '+PROJECT_PATH+'\\assets\\www\\cordova-'+VERSION+'.js /Y');
+    // copy in cordova.jar
+    exec('%comspec% /c copy "'+ROOT+'"\\cordova-'+VERSION+'.jar '+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar /Y');
+    // copy in xml
+}
+
+// update cordova scripts
+createAppInfoJar();
+WScript.Echo("Copying cordova command tools...");
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\appinfo.jar ' + PROJECT_PATH + '\\cordova\\appinfo.jar /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\cordova.js ' + PROJECT_PATH + '\\cordova\\cordova.js /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\cordova.bat ' + PROJECT_PATH + '\\cordova\\cordova.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\clean.bat ' + PROJECT_PATH + '\\cordova\\clean.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\build.bat ' + PROJECT_PATH + '\\cordova\\build.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\log.bat ' + PROJECT_PATH + '\\cordova\\log.bat /Y');
+exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\cordova\\run.bat ' + PROJECT_PATH + '\\cordova\\run.bat /Y');
+
+cleanup();

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/assets/js/cordova.android.js
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/assets/js/cordova.android.js b/lib/cordova-android/framework/assets/js/cordova.android.js
index bfd6545..a0c3278 100644
--- a/lib/cordova-android/framework/assets/js/cordova.android.js
+++ b/lib/cordova-android/framework/assets/js/cordova.android.js
@@ -1,8 +1,8 @@
 // Platform: android
 
-// commit f50d20a87431c79a54572263729461883f611a53
+// commit 47593b2bc1dba9bf46545b1da24577f937966e12
 
-// File generated at :: Tue Feb 26 2013 13:37:51 GMT-0800 (PST)
+// File generated at :: Thu Mar 21 2013 10:49:00 GMT-0700 (PDT)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -262,7 +262,7 @@ var cordova = {
      */
     callbackSuccess: function(callbackId, args) {
         try {
-            cordova.callbackFromNative(callbackId, true, args.status, args.message, args.keepCallback);
+            cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
         } catch (e) {
             console.log("Error in error callback: " + callbackId + " = "+e);
         }
@@ -275,7 +275,7 @@ var cordova = {
         // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
         // Derive success from status.
         try {
-            cordova.callbackFromNative(callbackId, false, args.status, args.message, args.keepCallback);
+            cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
         } catch (e) {
             console.log("Error in error callback: " + callbackId + " = "+e);
         }
@@ -284,13 +284,13 @@ var cordova = {
     /**
      * Called by native code when returning the result from an action.
      */
-    callbackFromNative: function(callbackId, success, status, message, keepCallback) {
+    callbackFromNative: function(callbackId, success, status, args, keepCallback) {
         var callback = cordova.callbacks[callbackId];
         if (callback) {
             if (success && status == cordova.callbackStatus.OK) {
-                callback.success && callback.success(message);
+                callback.success && callback.success.apply(null, args);
             } else if (!success) {
-                callback.fail && callback.fail(message);
+                callback.fail && callback.fail.apply(null, args);
             }
 
             // Clear callback if not expecting any more results
@@ -724,6 +724,9 @@ channel.createSticky('onCordovaInfoReady');
 // Event to indicate that the connection property has been set.
 channel.createSticky('onCordovaConnectionReady');
 
+// 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');
 
@@ -900,7 +903,7 @@ 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.');
+        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);
@@ -958,10 +961,12 @@ function processMessage(message) {
                     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);
+            cordova.callbackFromNative(callbackId, success, status, [payload], keepCallback);
         } else {
             console.log("processMessage failed: invalid message:" + message);
         }
@@ -1203,9 +1208,10 @@ cameraExport.getPicture = function(successCallback, errorCallback, options) {
     var correctOrientation = !!options.correctOrientation;
     var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
     var popoverOptions = getValue(options.popoverOptions, null);
+    var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
 
     var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
-                mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions];
+                mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
 
     exec(successCallback, errorCallback, "Camera", "takePicture", args);
     return new CameraPopoverHandle();
@@ -1248,6 +1254,10 @@ module.exports = {
       ARROW_LEFT : 4,
       ARROW_RIGHT : 8,
       ARROW_ANY : 15
+  },
+  Direction:{
+      BACK: 0,
+      FRONT: 1
   }
 };
 
@@ -2439,14 +2449,7 @@ FileReader.prototype.readAsText = function(file, encoding) {
     // Default encoding is UTF-8
     var enc = encoding ? encoding : "UTF-8";
     var me = this;
-    var execArgs = [this._fileName, enc];
-
-    // Maybe add slice parameters.
-    if (file.end < file.size) {
-        execArgs.push(file.start, file.end);
-    } else if (file.start > 0) {
-        execArgs.push(file.start);
-    }
+    var execArgs = [this._fileName, enc, file.start, file.end];
 
     // Read file
     exec(
@@ -2515,14 +2518,7 @@ FileReader.prototype.readAsDataURL = function(file) {
     }
 
     var me = this;
-    var execArgs = [this._fileName];
-
-    // Maybe add slice parameters.
-    if (file.end < file.size) {
-        execArgs.push(file.start, file.end);
-    } else if (file.start > 0) {
-        execArgs.push(file.start);
-    }
+    var execArgs = [this._fileName, file.start, file.end];
 
     // Read file
     exec(
@@ -2585,9 +2581,59 @@ FileReader.prototype.readAsBinaryString = function(file) {
     if (initRead(this, file)) {
         return this._realReader.readAsBinaryString(file);
     }
-    // TODO - Can't return binary data to browser.
-    console.log('method "readAsBinaryString" is not supported at this time.');
-    this.abort();
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsBinaryString", execArgs);
 };
 
 /**
@@ -2599,9 +2645,59 @@ FileReader.prototype.readAsArrayBuffer = function(file) {
     if (initRead(this, file)) {
         return this._realReader.readAsArrayBuffer(file);
     }
-    // TODO - Can't return binary data to browser.
-    console.log('This method is not supported at this time.');
-    this.abort();
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsArrayBuffer", execArgs);
 };
 
 module.exports = FileReader;
@@ -2647,6 +2743,38 @@ function newProgressEvent(result) {
     return pe;
 }
 
+function getBasicAuthHeader(urlString) {
+    var header =  null;
+
+    if (window.btoa) {
+        // parse the url using the Location object
+        var url = document.createElement('a');
+        url.href = urlString;
+
+        var credentials = null;
+        var protocol = url.protocol + "//";
+        var origin = protocol + url.host;
+
+        // check whether there are the username:password credentials in the url
+        if (url.href.indexOf(origin) != 0) { // credentials found
+            var atIndex = url.href.indexOf("@");
+            credentials = url.href.substring(protocol.length, atIndex);
+        }
+
+        if (credentials) {
+            var authHeader = "Authorization";
+            var authHeaderValue = "Basic " + window.btoa(credentials);
+
+            header = {
+                name : authHeader,
+                value : authHeaderValue
+            };
+        }
+    }
+
+    return header;
+}
+
 var idCounter = 0;
 
 /**
@@ -2677,6 +2805,18 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
     var params = null;
     var chunkedMode = true;
     var headers = null;
+
+    var basicAuthHeader = getBasicAuthHeader(server);
+    if (basicAuthHeader) {
+        if (!options) {
+            options = new FileUploadOptions();
+        }
+        if (!options.headers) {
+            options.headers = {};
+        }
+        options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+    }
+
     if (options) {
         fileKey = options.fileKey;
         fileName = options.fileName;
@@ -2694,7 +2834,7 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
     }
 
     var fail = errorCallback && function(e) {
-        var error = new FileTransferError(e.code, e.source, e.target, e.http_status);
+        var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
         errorCallback(error);
     };
 
@@ -2718,10 +2858,28 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
  * @param successCallback (Function}  Callback to be invoked when upload has completed
  * @param errorCallback {Function}    Callback to be invoked upon error
  * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false
+ * @param options {FileDownloadOptions} Optional parameters such as headers
  */
-FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts) {
+FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts, options) {
     argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments);
     var self = this;
+
+    var basicAuthHeader = getBasicAuthHeader(source);
+    if (basicAuthHeader) {
+        if (!options) {
+            options = {};
+        }
+        if (!options.headers) {
+            options.headers = {};
+        }
+        options.headers[basicAuthHeader.name] = basicAuthHeader.value;
+    }
+
+    var headers = null;
+    if (options) {
+        headers = options.headers || null;
+    }
+
     var win = function(result) {
         if (typeof result.lengthComputable != "undefined") {
             if (self.onprogress) {
@@ -2744,11 +2902,11 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro
     };
 
     var fail = errorCallback && function(e) {
-        var error = new FileTransferError(e.code, e.source, e.target, e.http_status);
+        var error = new FileTransferError(e.code, e.source, e.target, e.http_status, e.body);
         errorCallback(error);
     };
 
-    exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id]);
+    exec(win, fail, 'FileTransfer', 'download', [source, target, trustAllHosts, this._id, headers]);
 };
 
 /**
@@ -3146,6 +3304,7 @@ function InAppBrowser() {
    this.channels = {
         'loadstart': channel.create('loadstart'),
         'loadstop' : channel.create('loadstop'),
+        'loaderror' : channel.create('loaderror'),
         'exit' : channel.create('exit')
    };
 }
@@ -3176,7 +3335,7 @@ module.exports = function(strUrl, strWindowName, strWindowFeatures) {
     var cb = function(eventname) {
        iab._eventHandler(eventname);
     };
-    exec(cb, null, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
+    exec(cb, cb, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]);
     return iab;
 };
 
@@ -4940,7 +5099,8 @@ modulemapper.merges('cordova/plugin/android/device', 'device');
 // file: lib/common/plugin/echo.js
 define("cordova/plugin/echo", function(require, exports, module) {
 
-var exec = require('cordova/exec');
+var exec = require('cordova/exec'),
+    utils = require('cordova/utils');
 
 /**
  * Sends the given message through exec() to the Echo plugin, which sends it back to the successCallback.
@@ -4950,11 +5110,25 @@ var exec = require('cordova/exec');
  * @param forceAsync  Whether to force an async return value (for testing native->js bridge).
  */
 module.exports = function(successCallback, errorCallback, message, forceAsync) {
-    var action = forceAsync ? 'echoAsync' : 'echo';
-    if (!forceAsync && message.constructor == ArrayBuffer) {
-        action = 'echoArrayBuffer';
+    var action = 'echo';
+    var messageIsMultipart = (utils.typeName(message) == "Array");
+    var args = messageIsMultipart ? message : [message];
+
+    if (utils.typeName(message) == 'ArrayBuffer') {
+        if (forceAsync) {
+            console.warn('Cannot echo ArrayBuffer with forced async, falling back to sync.');
+        }
+        action += 'ArrayBuffer';
+    } else if (messageIsMultipart) {
+        if (forceAsync) {
+            console.warn('Cannot echo MultiPart Array with forced async, falling back to sync.');
+        }
+        action += 'MultiPart';
+    } else if (forceAsync) {
+        action += 'Async';
     }
-    exec(successCallback, errorCallback, "Echo", action, [message]);
+
+    exec(successCallback, errorCallback, "Echo", action, args);
 };
 
 
@@ -5950,6 +6124,7 @@ modulemapper.defaults('cordova/plugin/Connection', 'Connection');
 define("cordova/plugin/notification", function(require, exports, module) {
 
 var exec = require('cordova/exec');
+var platform = require('cordova/platform');
 
 /**
  * Provides access to notifications on the device.
@@ -5978,15 +6153,53 @@ module.exports = {
      * @param {String} message              Message to print in the body of the alert
      * @param {Function} resultCallback     The callback that is called when user clicks on a button.
      * @param {String} title                Title of the alert dialog (default: Confirm)
-     * @param {String} buttonLabels         Comma separated list of the labels of the buttons (default: 'OK,Cancel')
+     * @param {Array} buttonLabels          Array of the labels of the buttons (default: ['OK', 'Cancel'])
      */
     confirm: function(message, resultCallback, title, buttonLabels) {
         var _title = (title || "Confirm");
-        var _buttonLabels = (buttonLabels || "OK,Cancel");
+        var _buttonLabels = (buttonLabels || ["OK", "Cancel"]);
+
+        // Strings are deprecated!
+        if (typeof _buttonLabels === 'string') {
+            console.log("Notification.confirm(string, function, string, string) is deprecated.  Use Notification.confirm(string, function, string, array).");
+        }
+
+        // Android and iOS take an array of button label names.
+        // Other platforms take a comma separated list.
+        // For compatibility, we convert to the desired type based on the platform.
+        if (platform.id == "android" || platform.id == "ios") {
+            if (typeof _buttonLabels === 'string') {
+                var buttonLabelString = _buttonLabels;
+                _buttonLabels = buttonLabelString.split(",");
+            }
+        } else {
+            if (Array.isArray(_buttonLabels)) {
+                var buttonLabelArray = _buttonLabels;
+                _buttonLabels = buttonLabelArray.toString();
+            }
+        }
         exec(resultCallback, null, "Notification", "confirm", [message, _title, _buttonLabels]);
     },
 
     /**
+     * Open a native prompt dialog, with a customizable title and button text.
+     * The following results are returned to the result callback:
+     *  buttonIndex     Index number of the button selected.
+     *  input1          The text entered in the prompt dialog box.
+     *
+     * @param {String} message              Dialog message to display (default: "Prompt message")
+     * @param {Function} resultCallback     The callback that is called when user clicks on a button.
+     * @param {String} title                Title of the dialog (default: "Prompt")
+     * @param {Array} buttonLabels          Array of strings for the button labels (default: ["OK","Cancel"])
+     */
+    prompt: function(message, resultCallback, title, buttonLabels) {
+        var _message = (message || "Prompt message");
+        var _title = (title || "Prompt");
+        var _buttonLabels = (buttonLabels || ["OK","Cancel"]);
+        exec(resultCallback, null, "Notification", "prompt", [_message, _title, _buttonLabels]);
+    },
+
+    /**
      * Causes the device to vibrate.
      *
      * @param {Integer} mills       The number of milliseconds to vibrate for.
@@ -6409,53 +6622,160 @@ window.cordova = require('cordova');
 (function (context) {
     // 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.
-    if (context.navigator) {
+    function replaceNavigator(origNavigator) {
         var CordovaNavigator = function() {};
-        CordovaNavigator.prototype = context.navigator;
-        context.navigator = new CordovaNavigator();
+        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 (context.navigator) {
+        context.navigator = replaceNavigator(context.navigator);
+    }
+
+    var channel = require("cordova/channel");
+
+    // _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();
+    }
+
+    /**
+     * Create all cordova objects once page has fully loaded and native side is ready.
+     */
+    channel.join(function() {
+        var builder = require('cordova/builder'),
+            platform = require('cordova/platform');
+
+        builder.buildIntoButDoNotClobber(platform.defaults, context);
+        builder.buildIntoAndClobber(platform.clobbers, context);
+        builder.buildIntoAndMerge(platform.merges, context);
+
+        // Call the platform-specific initialization
+        platform.initialize();
+
+        // Fire event to notify that all objects are created
+        channel.onCordovaReady.fire();
+
+        // Fire onDeviceReady event once all constructors have run and
+        // cordova info has been received from native side.
+        channel.join(function() {
+            require('cordova').fireDocumentEvent('deviceready');
+        }, channel.deviceReadyChannelsArray);
+
+    }, [ channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady ]);
 
-    var channel = require("cordova/channel"),
-        _self = {
-            boot: function () {
-                /**
-                 * Create all cordova objects once page has fully loaded and native side is ready.
-                 */
-                channel.join(function() {
-                    var builder = require('cordova/builder'),
-                        platform = require('cordova/platform');
+}(window));
 
-                    builder.buildIntoButDoNotClobber(platform.defaults, context);
-                    builder.buildIntoAndClobber(platform.clobbers, context);
-                    builder.buildIntoAndMerge(platform.merges, context);
+// file: lib/scripts/plugin_loader.js
 
-                    // Call the platform-specific initialization
-                    platform.initialize();
+// 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.
+(function (context) {
+    // To be populated with the handler by handlePluginsObject.
+    var onScriptLoadingComplete;
+
+    var scriptCounter = 0;
+    function scriptLoadedCallback() {
+        scriptCounter--;
+        if (scriptCounter === 0) {
+            onScriptLoadingComplete && onScriptLoadingComplete();
+        }
+    }
 
-                    // Fire event to notify that all objects are created
-                    channel.onCordovaReady.fire();
+    // Helper function to inject a <script> tag.
+    function injectScript(path) {
+        scriptCounter++;
+        var script = document.createElement("script");
+        script.onload = scriptLoadedCallback;
+        script.src = path;
+        document.head.appendChild(script);
+    }
+
+    // Called when:
+    // * There are plugins defined and all plugins are finished loading.
+    // * There are no plugins to load.
+    function finishPluginLoading() {
+        context.cordova.require('cordova/channel').onPluginsReady.fire();
+    }
+
+    // Handler for the cordova_plugins.json 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 XHR response handler will just call finishPluginLoading().
+    function handlePluginsObject(modules) {
+        // First create the callback for when all plugins are loaded.
+        var mapper = context.cordova.require('cordova/modulemapper');
+        onScriptLoadingComplete = function() {
+            // Loop through all the plugins and then through their clobbers and merges.
+            for (var i = 0; i < modules.length; i++) {
+                var module = modules[i];
+                if (!module) continue;
+
+                if (module.clobbers && module.clobbers.length) {
+                    for (var j = 0; j < module.clobbers.length; j++) {
+                        mapper.clobbers(module.id, module.clobbers[j]);
+                    }
+                }
 
-                    // Fire onDeviceReady event once all constructors have run and
-                    // cordova info has been received from native side.
-                    channel.join(function() {
-                        require('cordova').fireDocumentEvent('deviceready');
-                    }, channel.deviceReadyChannelsArray);
+                if (module.merges && module.merges.length) {
+                    for (var k = 0; k < module.merges.length; k++) {
+                        mapper.merges(module.id, module.merges[k]);
+                    }
+                }
 
-                }, [ channel.onDOMContentLoaded, channel.onNativeReady ]);
+                // 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)) {
+                    context.cordova.require(module.id);
+                }
             }
-        };
 
-    // boot up once native side is ready
-    channel.onNativeReady.subscribe(_self.boot);
+            finishPluginLoading();
+        };
 
-    // _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();
+        // Now inject the scripts.
+        for (var i = 0; i < modules.length; i++) {
+            injectScript(modules[i].file);
+        }
     }
 
+    // Try to XHR the cordova_plugins.json file asynchronously.
+    var xhr = new context.XMLHttpRequest();
+    xhr.onreadystatechange = function() {
+        if (this.readyState != 4) { // not DONE
+            return;
+        }
+
+        // If the response is a JSON string which composes an array, call handlePluginsObject.
+        // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
+        if (this.status == 200) {
+            var obj = JSON.parse(this.responseText);
+            if (obj && obj instanceof Array && obj.length > 0) {
+                handlePluginsObject(obj);
+            } else {
+                finishPluginLoading();
+            }
+        } else {
+            finishPluginLoading();
+        }
+    };
+    xhr.open('GET', 'cordova_plugins.json', true); // Async
+    xhr.send();
 }(window));
 
 
+
 })();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/assets/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/assets/www/index.html b/lib/cordova-android/framework/assets/www/index.html
index a10905d..3b15a4e 100644
--- a/lib/cordova-android/framework/assets/www/index.html
+++ b/lib/cordova-android/framework/assets/www/index.html
@@ -19,7 +19,7 @@
 <html>
   <head>
     <title></title>
-    <script src="cordova-2.5.0.js"></script>
+    <script src="cordova-2.6.0rc1.js"></script>
   </head>
   <body>
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/AudioHandler.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/AudioHandler.java b/lib/cordova-android/framework/src/org/apache/cordova/AudioHandler.java
index ed5757f..fd8c9df 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/AudioHandler.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/AudioHandler.java
@@ -68,13 +68,13 @@ public class AudioHandler extends CordovaPlugin {
         String result = "";
 
         if (action.equals("startRecordingAudio")) {
-            this.startRecordingAudio(args.getString(0), FileUtils.stripFileProtocol(args.getString(1)));
+            this.startRecordingAudio(args.getString(0), FileHelper.stripFileProtocol(args.getString(1)));
         }
         else if (action.equals("stopRecordingAudio")) {
             this.stopRecordingAudio(args.getString(0));
         }
         else if (action.equals("startPlayingAudio")) {
-            this.startPlayingAudio(args.getString(0), FileUtils.stripFileProtocol(args.getString(1)));
+            this.startPlayingAudio(args.getString(0), FileHelper.stripFileProtocol(args.getString(1)));
         }
         else if (action.equals("seekToAudio")) {
             this.seekToAudio(args.getString(0), args.getInt(1));
@@ -102,7 +102,7 @@ public class AudioHandler extends CordovaPlugin {
         }
         else if (action.equals("create")) {
             String id = args.getString(0);
-            String src = FileUtils.stripFileProtocol(args.getString(1));
+            String src = FileHelper.stripFileProtocol(args.getString(1));
             AudioPlayer audio = new AudioPlayer(this, id, src);
             this.players.put(id, audio);
         }

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/AudioPlayer.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/AudioPlayer.java b/lib/cordova-android/framework/src/org/apache/cordova/AudioPlayer.java
index 99dbb3d..0170728 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/AudioPlayer.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/AudioPlayer.java
@@ -167,13 +167,18 @@ public class AudioPlayer implements OnCompletionListener, OnPreparedListener, On
     public void moveFile(String file) {
         /* this is a hack to save the file as the specified name */
         File f = new File(this.tempFile);
-        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
-            f.renameTo(new File(Environment.getExternalStorageDirectory().getAbsolutePath()
-                    + File.separator + file));
-        } else {
-            f.renameTo(new File("/data/data/" + handler.cordova.getActivity().getPackageName() + "/cache/" + file));
+
+        if (!file.startsWith("/")) {
+            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+                file = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + file;
+            } else {
+                file = "/data/data/" + handler.cordova.getActivity().getPackageName() + "/cache/" + file;
+            }
         }
 
+        String logMsg = "renaming " + this.tempFile + " to " + file;
+        Log.d(LOG_TAG, logMsg);
+        if (!f.renameTo(new File(file))) Log.e(LOG_TAG, "FAILED " + logMsg);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java b/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
index aec0def..9473828 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
@@ -289,7 +289,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
 
                     // If sending base64 image back
                     if (destType == DATA_URL) {
-                        bitmap = getScaledBitmap(FileUtils.stripFileProtocol(imageUri.toString()));
+                        bitmap = getScaledBitmap(FileHelper.stripFileProtocol(imageUri.toString()));
                         if (bitmap == null) {
                             // Try to get the bitmap from intent.
                             bitmap = (Bitmap)intent.getExtras().get("data");
@@ -329,7 +329,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
 
                             this.callbackContext.success(uri.toString());
                         } else {
-                            bitmap = getScaledBitmap(FileUtils.stripFileProtocol(imageUri.toString()));
+                            bitmap = getScaledBitmap(FileHelper.stripFileProtocol(imageUri.toString()));
 
                             if (rotate != 0 && this.correctOrientation) {
                                 bitmap = getRotatedBitmap(rotate, bitmap, exif);
@@ -344,7 +344,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                             if (this.encodingType == JPEG) {
                                 String exifPath;
                                 if (this.saveToPhotoAlbum) {
-                                    exifPath = FileUtils.getRealPathFromURI(uri, this.cordova);
+                                    exifPath = FileHelper.getRealPath(uri, this.cordova);
                                 } else {
                                     exifPath = uri.getPath();
                                 }
@@ -395,8 +395,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                         this.callbackContext.success(uri.toString());
                     } else {
                         // Get the path to the image. Makes loading so much easier.
-                        String imagePath = FileUtils.getRealPathFromURI(uri, this.cordova);
-                        String mimeType = FileUtils.getMimeType(imagePath);
+                        String imagePath = FileHelper.getRealPath(uri, this.cordova);
+                        String mimeType = FileHelper.getMimeType(imagePath, this.cordova);
                         // Log.d(LOG_TAG, "Real path = " + imagePath);
                         // Log.d(LOG_TAG, "mime type = " + mimeType);
                         // If we don't have a valid image so quit.
@@ -458,7 +458,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
 
                                     // Restore exif data to file
                                     if (this.encodingType == JPEG) {
-                                        exif.createOutFile(FileUtils.getRealPathFromURI(uri, this.cordova));
+                                        exif.createOutFile(FileHelper.getRealPath(uri, this.cordova));
                                         exif.writeExifData();
                                     }
 
@@ -521,7 +521,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
      */
     private void writeUncompressedImage(Uri uri) throws FileNotFoundException,
             IOException {
-        FileInputStream fis = new FileInputStream(FileUtils.stripFileProtocol(imageUri.toString()));
+        FileInputStream fis = new FileInputStream(FileHelper.stripFileProtocol(imageUri.toString()));
         OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
         byte[] buffer = new byte[4096];
         int len;
@@ -685,7 +685,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
         }
 
         // Clean up initial camera-written image file.
-        (new File(FileUtils.stripFileProtocol(oldImage.toString()))).delete();
+        (new File(FileHelper.stripFileProtocol(oldImage.toString()))).delete();
 
         checkForDuplicateImage(imageType);
         // Scan for the gallery to update pic refs in gallery

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/Capture.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/Capture.java b/lib/cordova-android/framework/src/org/apache/cordova/Capture.java
index 3eecf37..5f737ca 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/Capture.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/Capture.java
@@ -23,6 +23,7 @@ import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 
+import android.os.Build;
 import org.apache.cordova.api.CallbackContext;
 import org.apache.cordova.api.CordovaPlugin;
 import org.apache.cordova.api.LOG;
@@ -128,7 +129,7 @@ public class Capture extends CordovaPlugin {
         // If the mimeType isn't set the rest will fail
         // so let's see if we can determine it.
         if (mimeType == null || mimeType.equals("") || "null".equals(mimeType)) {
-            mimeType = FileUtils.getMimeType(filePath);
+            mimeType = FileHelper.getMimeType(filePath, cordova);
         }
         Log.d(LOG_TAG, "Mime type = " + mimeType);
 
@@ -155,7 +156,7 @@ public class Capture extends CordovaPlugin {
     private JSONObject getImageData(String filePath, JSONObject obj) throws JSONException {
         BitmapFactory.Options options = new BitmapFactory.Options();
         options.inJustDecodeBounds = true;
-        BitmapFactory.decodeFile(FileUtils.stripFileProtocol(filePath), options);
+        BitmapFactory.decodeFile(FileHelper.stripFileProtocol(filePath), options);
         obj.put("height", options.outHeight);
         obj.put("width", options.outWidth);
         return obj;
@@ -216,9 +217,10 @@ public class Capture extends CordovaPlugin {
      */
     private void captureVideo(double duration) {
         Intent intent = new Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE);
-        // Introduced in API 8
-        //intent.putExtra(android.provider.MediaStore.EXTRA_DURATION_LIMIT, duration);
 
+        if(Build.VERSION.SDK_INT > 8){
+            intent.putExtra("android.intent.extra.durationLimit", duration);
+        }
         this.cordova.startActivityForResult((CordovaPlugin) this, intent, CAPTURE_VIDEO);
     }
 
@@ -346,7 +348,7 @@ public class Capture extends CordovaPlugin {
      * @throws IOException
      */
     private JSONObject createMediaFile(Uri data) {
-        File fp = new File(FileUtils.getRealPathFromURI(data, this.cordova));
+        File fp = new File(FileHelper.getRealPath(data, this.cordova));
         JSONObject obj = new JSONObject();
 
         try {
@@ -363,7 +365,7 @@ public class Capture extends CordovaPlugin {
                     obj.put("type", VIDEO_3GPP);
                 }
             } else {
-                obj.put("type", FileUtils.getMimeType(fp.getAbsolutePath()));
+                obj.put("type", FileHelper.getMimeType(fp.getAbsolutePath(), cordova));
             }
 
             obj.put("lastModifiedDate", fp.lastModified());

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/Config.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/Config.java b/lib/cordova-android/framework/src/org/apache/cordova/Config.java
index 01eb2bb..f5de38d 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/Config.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/Config.java
@@ -143,6 +143,16 @@ public class Config {
                         boolean value = xml.getAttributeValue(null, "value").equals("true");
                         action.getIntent().putExtra(name, value);
                     }
+                    else if(name.equals("InAppBrowserStorageEnabled"))
+                    {
+                        boolean value = xml.getAttributeValue(null, "value").equals("true");
+                        action.getIntent().putExtra(name, value);
+                    }
+                    else if(name.equals("disallowOverscroll"))
+                    {
+                        boolean value = xml.getAttributeValue(null, "value").equals("true");
+                        action.getIntent().putExtra(name, value);
+                    }
                     else
                     {
                         String value = xml.getAttributeValue(null, "value");

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/CordovaArgs.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/CordovaArgs.java b/lib/cordova-android/framework/src/org/apache/cordova/CordovaArgs.java
index 3a8b7c0..d40d26e 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/CordovaArgs.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CordovaArgs.java
@@ -20,6 +20,7 @@ package org.apache.cordova;
 
 import org.json.JSONArray;
 import org.json.JSONException;
+import org.json.JSONObject;
 
 import android.util.Base64;
 
@@ -52,7 +53,7 @@ public class CordovaArgs {
         return baseArgs.getJSONArray(index);
     }
 
-    public Object getJSONObject(int index) throws JSONException {
+    public JSONObject getJSONObject(int index) throws JSONException {
         return baseArgs.getJSONObject(index);
     }
 
@@ -85,7 +86,7 @@ public class CordovaArgs {
         return baseArgs.optJSONArray(index);
     }
 
-    public Object optJSONObject(int index) {
+    public JSONObject optJSONObject(int index) {
         return baseArgs.optJSONObject(index);
     }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/CordovaChromeClient.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/CordovaChromeClient.java b/lib/cordova-android/framework/src/org/apache/cordova/CordovaChromeClient.java
index e650781..fb6d45f 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/CordovaChromeClient.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CordovaChromeClient.java
@@ -205,7 +205,7 @@ public class CordovaChromeClient extends WebChromeClient {
         // Security check to make sure any requests are coming from the page initially
         // loaded in webview and not another loaded in an iframe.
         boolean reqOk = false;
-        if (url.startsWith("file://") || url.indexOf(this.appView.baseUrl) == 0 || Config.isUrlWhiteListed(url)) {
+        if (url.startsWith("file://") || Config.isUrlWhiteListed(url)) {
             reqOk = true;
         }
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebView.java
----------------------------------------------------------------------
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebView.java b/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebView.java
index 4731adb..e653a95 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebView.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebView.java
@@ -47,6 +47,7 @@ import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
 import android.webkit.WebBackForwardList;
 import android.webkit.WebHistoryItem;
 import android.webkit.WebChromeClient;
@@ -74,12 +75,7 @@ public class CordovaWebView extends WebView {
     @SuppressWarnings("unused")
     private CordovaChromeClient chromeClient;
 
-    //This is for the polyfill history
     private String url;
-    String baseUrl;
-    private Stack<String> urls = new Stack<String>();
-
-    boolean useBrowserHistory = true;
 
     // Flag to track that a loadUrl timeout occurred
     int loadUrlTimeout = 0;
@@ -211,7 +207,8 @@ public class CordovaWebView extends WebView {
 
 
     private void initWebViewClient(CordovaInterface cordova) {
-        if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
+        if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB ||
+                android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.JELLY_BEAN_MR1)
         {
             this.setWebViewClient(new CordovaWebViewClient(this.cordova, this));
         }
@@ -254,14 +251,23 @@ public class CordovaWebView extends WebView {
             Log.d(TAG, "This should never happen: InvocationTargetException means this isn't Android anymore.");
         }
 
+        //We don't save any form data in the application
+        settings.setSaveFormData(false);
+        settings.setSavePassword(false);
+        
         // Jellybean rightfully tried to lock this down. Too bad they didn't give us a whitelist
         // while we do this
         if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
             Level16Apis.enableUniversalAccess(settings);
         // Enable database
-        settings.setDatabaseEnabled(true);
+        // We keep this disabled because we use or shim to get around DOM_EXCEPTION_ERROR_16
         String databasePath = this.cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
-        settings.setDatabasePath(databasePath);
+        if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
+        {
+            settings.setDatabaseEnabled(true);
+            settings.setDatabasePath(databasePath);
+        }
+        
         settings.setGeolocationDatabasePath(databasePath);
 
         // Enable DOM storage
@@ -360,7 +366,7 @@ public class CordovaWebView extends WebView {
             String initUrl = this.getProperty("url", null);
 
             // If first page of app, then set URL to load to be the one passed in
-            if (initUrl == null || (this.urls.size() > 0)) {
+            if (initUrl == null) {
                 this.loadUrlIntoView(url);
             }
             // Otherwise use the URL specified in the activity's extras bundle
@@ -381,7 +387,7 @@ public class CordovaWebView extends WebView {
         String initUrl = this.getProperty("url", null);
 
         // If first page of app, then set URL to load to be the one passed in
-        if (initUrl == null || (this.urls.size() > 0)) {
+        if (initUrl == null) {
             this.loadUrlIntoView(url, time);
         }
         // Otherwise use the URL specified in the activity's extras bundle
@@ -399,21 +405,8 @@ public class CordovaWebView extends WebView {
         LOG.d(TAG, ">>> loadUrl(" + url + ")");
 
         this.url = url;
-        if (this.baseUrl == null) {
-            int i = url.lastIndexOf('/');
-            if (i > 0) {
-                this.baseUrl = url.substring(0, i + 1);
-            }
-            else {
-                this.baseUrl = this.url + "/";
-            }
-
-            this.pluginManager.init();
+        this.pluginManager.init();
 
-            if (!this.useBrowserHistory) {
-                this.urls.push(url);
-            }
-        }
 
         // Create a timeout timer for loadUrl
         final CordovaWebView me = this;
@@ -468,7 +461,7 @@ public class CordovaWebView extends WebView {
         if (LOG.isLoggable(LOG.DEBUG) && !url.startsWith("javascript:")) {
             LOG.d(TAG, ">>> loadUrlNow()");
         }
-        if (url.startsWith("file://") || url.indexOf(this.baseUrl) == 0 || url.startsWith("javascript:") || Config.isUrlWhiteListed(url)) {
+        if (url.startsWith("file://") || url.startsWith("javascript:") || Config.isUrlWhiteListed(url)) {
             super.loadUrl(url);
         }
     }
@@ -484,7 +477,7 @@ public class CordovaWebView extends WebView {
 
         // If not first page of app, then load immediately
         // Add support for browser history if we use it.
-        if ((url.startsWith("javascript:")) || this.urls.size() > 0 || this.canGoBack()) {
+        if ((url.startsWith("javascript:")) || this.canGoBack()) {
         }
 
         // If first page, then show splashscreen
@@ -532,25 +525,6 @@ public class CordovaWebView extends WebView {
         }
     }
 
-    /**
-     * Returns the top url on the stack without removing it from
-     * the stack.
-     */
-    public String peekAtUrlStack() {
-        if (this.urls.size() > 0) {
-            return this.urls.peek();
-        }
-        return "";
-    }
-
-    /**
-     * Add a url to the stack
-     *
-     * @param url
-     */
-    public void pushUrl(String url) {
-        this.urls.push(url);
-    }
 
     /**
      * Go to previous page in history.  (We manage our own history)
@@ -561,37 +535,15 @@ public class CordovaWebView extends WebView {
 
         // Check webview first to see if there is a history
         // This is needed to support curPage#diffLink, since they are added to appView's history, but not our history url array (JQMobile behavior)
-        if (super.canGoBack() && this.useBrowserHistory) {
+        if (super.canGoBack()) {
             printBackForwardList();
             super.goBack();
             
             return true;
         }
-        // If our managed history has prev url
-        else if (this.urls.size() > 1 && !this.useBrowserHistory) {
-            this.urls.pop();                // Pop current url
-            String url = this.urls.pop();   // Pop prev url that we want to load, since it will be added back by loadUrl()
-            this.loadUrl(url);
-            return true;
-        }
-
         return false;
     }
 
-    /**
-     * Return true if there is a history item.
-     *
-     * @return
-     */
-    public boolean canGoBack() {
-        if (super.canGoBack() && this.useBrowserHistory) {
-            return true;
-        }
-        else if (this.urls.size() > 1) {
-            return true;
-        }
-        return false;
-    }
 
     /**
      * Load the specified URL in the Cordova webview or a new browser instance.
@@ -615,14 +567,8 @@ public class CordovaWebView extends WebView {
         if (!openExternal) {
 
             // Make sure url is in whitelist
-            if (url.startsWith("file://") || url.indexOf(this.baseUrl) == 0 || Config.isUrlWhiteListed(url)) {
+            if (url.startsWith("file://") || Config.isUrlWhiteListed(url)) {
                 // TODO: What about params?
-
-                // Clear out current url from history, since it will be replacing it
-                if (clearHistory) {
-                    this.urls.clear();
-                }
-
                 // Load new URL
                 this.loadUrl(url);
             }
@@ -659,13 +605,6 @@ public class CordovaWebView extends WebView {
      *      <log level="DEBUG" />
      */
     private void loadConfiguration() {
-        // Config has already been loaded, and it stores these preferences on the Intent.
-        if("false".equals(this.getProperty("useBrowserHistory", "true")))
-        {
-            //Switch back to the old browser history and state the six month policy
-            this.useBrowserHistory = false;
-            Log.w(TAG, "useBrowserHistory=false is deprecated as of Cordova 2.2.0 and will be removed six months after the 2.2.0 release.  Please use the browser history and use history.back().");
-        }
  
         if ("true".equals(this.getProperty("fullscreen", "false"))) {
             this.cordova.getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
@@ -719,13 +658,20 @@ public class CordovaWebView extends WebView {
         }
         else if(keyCode == KeyEvent.KEYCODE_BACK)
         {
-            //Because exit is fired on the keyDown and not the key up on Android 4.x
-            //we need to check for this.
-            //Also, I really wished "canGoBack" worked!
-            if(this.useBrowserHistory)
-                return !(this.startOfHistory()) || this.bound;
-            else
-                return this.urls.size() > 1 || this.bound;
+            return !(this.startOfHistory()) || this.bound;
+        }
+        else if(keyCode == KeyEvent.KEYCODE_MENU)
+        {
+            //How did we get here?  Is there a childView?
+            View childView = this.getFocusedChild();
+            if(childView != null)
+            {
+                //Make sure we close the keyboard if it's present
+                InputMethodManager imm = (InputMethodManager) cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
+                imm.hideSoftInputFromWindow(childView.getWindowToken(), 0);
+                cordova.getActivity().openOptionsMenu();
+            }
+            return true;
         }
         
         return super.onKeyDown(keyCode, event);


[12/43] git commit: Fix 'plugin add' tests

Posted by an...@apache.org.
Fix 'plugin add' tests


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

Branch: refs/heads/master
Commit: be6d2edff3826d865bcfe0b549379a9661d1686a
Parents: 740ff28
Author: Braden Shepherdson <br...@gmail.com>
Authored: Tue Apr 9 15:59:27 2013 -0400
Committer: Braden Shepherdson <br...@gmail.com>
Committed: Tue Apr 9 15:59:27 2013 -0400

----------------------------------------------------------------------
 spec/plugin.spec.js |   22 ++--------------------
 1 files changed, 2 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/be6d2edf/spec/plugin.spec.js
----------------------------------------------------------------------
diff --git a/spec/plugin.spec.js b/spec/plugin.spec.js
index 787747f..12d893c 100644
--- a/spec/plugin.spec.js
+++ b/spec/plugin.spec.js
@@ -87,24 +87,6 @@ describe('plugin command', function() {
             process.chdir(cwd);
         });
         describe('failure', function() {
-            it('should throw if your app has no platforms added', function() {
-                expect(function() {
-                    cordova.plugin('add', testPlugin);
-                }).toThrow('You need at least one platform added to your app. Use `cordova platform add <platform>`.');
-            });
-            it('should throw if plugin does not support any app platforms', function() {
-                process.chdir(cordova_project);
-                shell.mv('-f', path.join(cordova_project, 'platforms', 'android'), tempDir);
-                shell.mv('-f', path.join(cordova_project, 'platforms', 'blackberry'), tempDir);
-                this.after(function() {
-                    process.chdir(cwd);
-                    shell.mv('-f', path.join(tempDir, 'android'), path.join(cordova_project, 'platforms'));
-                    shell.mv('-f', path.join(tempDir, 'blackberry'), path.join(cordova_project, 'platforms'));
-                });
-                expect(function() {
-                    cordova.plugin('add', androidPlugin);
-                }).toThrow('Plugin "android" does not support any of your application\'s platforms. Plugin platforms: android; your application\'s platforms: ios');
-            });
             it('should throw if plugin is already added to project', function() {
                 process.chdir(cordova_project);
                 var cb = jasmine.createSpy();
@@ -120,7 +102,7 @@ describe('plugin command', function() {
                 runs(function(){
                     expect(function() {
                         cordova.plugin('add', testPlugin);
-                    }).toThrow('Plugin "test" already added to project.');
+                    }).toThrow();
                 });
             });
             it('should throw if plugin does not have a plugin.xml', function() {
@@ -130,7 +112,7 @@ describe('plugin command', function() {
                 });
                 expect(function() {
                     cordova.plugin('add', fixturesDir);
-                }).toThrow('Plugin "fixtures" does not have a plugin.xml in the root. Plugin must support the Cordova Plugin Specification: https://github.com/alunny/cordova-plugin-spec');
+                }).toThrow();
             });
         });
     });


[40/43] git commit: [CB-3238] Update cordova-ios to 2.7.0

Posted by an...@apache.org.
[CB-3238] Update cordova-ios to 2.7.0


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

Branch: refs/heads/master
Commit: 0f619a723bd8d7553cfbcd56f48c9bb679caf89c
Parents: dac8583
Author: Michael Brooks <mi...@michaelbrooks.ca>
Authored: Tue Apr 30 13:23:40 2013 -0700
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu May 9 15:56:00 2013 -0700

----------------------------------------------------------------------
 .../CordovaLib/Classes/CDVInAppBrowser.h           |    2 +-
 .../CordovaLib/Classes/CDVInAppBrowser.m           |   34 +++++++++------
 lib/cordova-ios/CordovaLib/VERSION                 |    2 +-
 lib/cordova-ios/CordovaLib/cordova.ios.js          |   24 +++++++---
 lib/cordova-ios/RELEASENOTES.md                    |    2 +
 .../screen/ios/screen-iphone-portrait-568h-2x.png  |  Bin 0 -> 34225 bytes
 6 files changed, 40 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0f619a72/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
index 343f40d..765326a 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.h
@@ -55,7 +55,7 @@
 
 @property (nonatomic, weak) id <CDVScreenOrientationDelegate> orientationDelegate;
 @property (nonatomic, weak) CDVInAppBrowser* navigationDelegate;
-@property (nonatomic) NSURL* requestedURL;
+@property (nonatomic) NSURL* currentURL;
 
 - (void)close;
 - (void)navigateTo:(NSURL*)url;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0f619a72/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
index f366bd8..b03d1fe 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
@@ -253,6 +253,7 @@
 - (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
 {
     NSURL* url = request.URL;
+    BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]];
 
     // See if the url uses the 'gap-iab' protocol. If so, the host should be the id of a callback to execute,
     // and the path, if present, should be a JSON-encoded value to pass to the callback.
@@ -279,28 +280,28 @@
             [self.commandDelegate sendPluginResult:pluginResult callbackId:scriptCallbackId];
             return NO;
         }
+    } else if ((self.callbackId != nil) && isTopLevelNavigation) {
+        // Send a loadstart event for each top-level navigation (includes redirects).
+        CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
+                                                      messageAsDictionary:@{@"type":@"loadstart", @"url":[url absoluteString]}];
+        [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
+
+        [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
     }
+
     return YES;
 }
 
 - (void)webViewDidStartLoad:(UIWebView*)theWebView
 {
     _injectedIframeBridge = NO;
-    if (self.callbackId != nil) {
-        NSString* url = [[self.inAppBrowserViewController requestedURL] absoluteString];
-        CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
-                                                      messageAsDictionary:@{@"type":@"loadstart", @"url":url}];
-        [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
-
-        [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
-    }
 }
 
 - (void)webViewDidFinishLoad:(UIWebView*)theWebView
 {
     if (self.callbackId != nil) {
         // TODO: It would be more useful to return the URL the page is actually on (e.g. if it's been redirected).
-        NSString* url = [[self.inAppBrowserViewController requestedURL] absoluteString];
+        NSString* url = [self.inAppBrowserViewController.currentURL absoluteString];
         CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
                                                       messageAsDictionary:@{@"type":@"loadstop", @"url":url}];
         [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
@@ -312,7 +313,7 @@
 - (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error
 {
     if (self.callbackId != nil) {
-        NSString* url = [[self.inAppBrowserViewController requestedURL] absoluteString];
+        NSString* url = [self.inAppBrowserViewController.currentURL absoluteString];
         CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR
                                                       messageAsDictionary:@{@"type":@"loaderror", @"url":url, @"code": [NSNumber numberWithInt:error.code], @"message": error.localizedDescription}];
         [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
@@ -341,7 +342,7 @@
 
 @implementation CDVInAppBrowserViewController
 
-@synthesize requestedURL = _requestedURL;
+@synthesize currentURL;
 
 - (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent
 {
@@ -517,6 +518,8 @@
         [[self parentViewController] dismissModalViewControllerAnimated:YES];
     }
 
+    self.currentURL = nil;
+
     if ((self.navigationDelegate != nil) && [self.navigationDelegate respondsToSelector:@selector(browserExit)]) {
         [self.navigationDelegate browserExit];
     }
@@ -526,8 +529,6 @@
 {
     NSURLRequest* request = [NSURLRequest requestWithURL:url];
 
-    _requestedURL = url;
-
     if (_userAgentLockToken != 0) {
         [self.webView loadRequest:request];
     } else {
@@ -566,6 +567,11 @@
 
 - (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
 {
+    BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]];
+
+    if (isTopLevelNavigation) {
+        self.currentURL = request.URL;
+    }
     return [self.navigationDelegate webView:theWebView shouldStartLoadWithRequest:request navigationType:navigationType];
 }
 
@@ -573,7 +579,7 @@
 {
     // update url, stop spinner, update back/forward
 
-    self.addressLabel.text = theWebView.request.URL.absoluteString;
+    self.addressLabel.text = [self.currentURL absoluteString];
     self.backButton.enabled = theWebView.canGoBack;
     self.forwardButton.enabled = theWebView.canGoForward;
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0f619a72/lib/cordova-ios/CordovaLib/VERSION
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/VERSION b/lib/cordova-ios/CordovaLib/VERSION
index 59b7056..24ba9a3 100644
--- a/lib/cordova-ios/CordovaLib/VERSION
+++ b/lib/cordova-ios/CordovaLib/VERSION
@@ -1 +1 @@
-2.7.0rc1
+2.7.0

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0f619a72/lib/cordova-ios/CordovaLib/cordova.ios.js
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLib/cordova.ios.js b/lib/cordova-ios/CordovaLib/cordova.ios.js
index 844816f..b716939 100644
--- a/lib/cordova-ios/CordovaLib/cordova.ios.js
+++ b/lib/cordova-ios/CordovaLib/cordova.ios.js
@@ -1,8 +1,8 @@
 // Platform: ios
 
-// commit 360bd3e65c33ce4f01e2efb82d641a565ef3c333
+// commit cd29cf0f224ccf25e9d422a33fd02ef67d3a78f4
 
-// File generated at :: Fri Apr 19 2013 18:36:09 GMT-0700 (PDT)
+// File generated at :: Mon Apr 29 2013 16:14:47 GMT-0700 (PDT)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -909,11 +909,19 @@ function iOSExec() {
         // an invalid callbackId and passes it even if no callbacks were given.
         callbackId = 'INVALID';
     } else {
-        // FORMAT TWO
-        splitCommand = arguments[0].split(".");
-        action = splitCommand.pop();
-        service = splitCommand.join(".");
-        actionArgs = Array.prototype.splice.call(arguments, 1);
+        // FORMAT TWO, REMOVED
+       try {
+           splitCommand = arguments[0].split(".");
+           action = splitCommand.pop();
+           service = splitCommand.join(".");
+           actionArgs = Array.prototype.splice.call(arguments, 1);
+
+           console.log('The old format of this exec call has been removed (deprecated since 2.1). Change to: ' +
+                       "cordova.exec(null, null, \"" + service + "\", " + action + "\"," + JSON.stringify(actionArgs) + ");"
+                       );
+           return;
+       } catch (e) {
+       }
     }
 
     // Register the callbacks and add the callbackId to the positional
@@ -6388,7 +6396,7 @@ require('cordova/channel').onNativeReady.fire();
         xhr.onload = function() {
             // If the response is a JSON string which composes an array, call handlePluginsObject.
             // If the request fails, or the response is not a JSON array, just call finishPluginLoading.
-            var obj = JSON.parse(this.responseText);
+            var obj = this.responseText && JSON.parse(this.responseText);
             if (obj && obj instanceof Array && obj.length > 0) {
                 handlePluginsObject(obj);
             } else {

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0f619a72/lib/cordova-ios/RELEASENOTES.md
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/RELEASENOTES.md b/lib/cordova-ios/RELEASENOTES.md
index ffe0c0b..3c2031a 100644
--- a/lib/cordova-ios/RELEASENOTES.md
+++ b/lib/cordova-ios/RELEASENOTES.md
@@ -58,6 +58,8 @@
 * [CB-2896] split writing of working tags off here, multipart tags not supported
 * [CB-2896] fixed error in exif subifd offset calculation for tag 8769
 * [CB-2902] re-added long/short tags to template dict, fixed subExifIFD offset
+* [CB-2698] Fix load detection when pages have redirects.
+* [CB-3295] Send InAppBrowser loadstart events when redirects occur
 
 <br />
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/0f619a72/lib/cordova-ios/bin/templates/project/www/res/screen/ios/screen-iphone-portrait-568h-2x.png
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/www/res/screen/ios/screen-iphone-portrait-568h-2x.png b/lib/cordova-ios/bin/templates/project/www/res/screen/ios/screen-iphone-portrait-568h-2x.png
new file mode 100644
index 0000000..10ed683
Binary files /dev/null and b/lib/cordova-ios/bin/templates/project/www/res/screen/ios/screen-iphone-portrait-568h-2x.png differ


[32/43] git commit: [npm] Version 2.7.1-rc.1

Posted by an...@apache.org.
[npm] Version 2.7.1-rc.1


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

Branch: refs/heads/master
Commit: e6ca7df5ba4248d14d34d0ea4bd5be4060078c35
Parents: bca5ebf
Author: Michael Brooks <mi...@michaelbrooks.ca>
Authored: Wed Apr 24 17:44:58 2013 -0700
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu May 9 15:03:57 2013 -0700

----------------------------------------------------------------------
 package.json |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/e6ca7df5/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index eede08a..2d54e7b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "cordova",
-  "version": "2.7.0-rc.1",
+  "version": "2.7.1-rc.1",
   "preferGlobal": "true",
   "description": "Cordova command line interface tool",
   "main": "cordova",


[29/43] git commit: [npm] Version 2.6.2

Posted by an...@apache.org.
[npm] Version 2.6.2


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

Branch: refs/heads/master
Commit: ee26ee91aca666c5dc8e1238f6adf4282fd56b27
Parents: f03b1e4
Author: Michael Brooks <mi...@michaelbrooks.ca>
Authored: Wed Apr 17 16:53:12 2013 -0600
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu May 9 14:26:07 2013 -0700

----------------------------------------------------------------------
 package.json |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/ee26ee91/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index 563e222..04c45f6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "cordova",
-  "version": "2.6.1",
+  "version": "2.6.2",
   "preferGlobal": "true",
   "description": "Cordova command line interface tool",
   "main": "cordova",


[06/43] git commit: Install all installed plugins into a newly added platform

Posted by an...@apache.org.
Install all installed plugins into a newly added platform


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

Branch: refs/heads/master
Commit: 2f398403a2601f9f2b94af46ea04334197e152d6
Parents: 19d6966
Author: Braden Shepherdson <br...@gmail.com>
Authored: Mon Apr 8 16:38:10 2013 -0400
Committer: Braden Shepherdson <br...@gmail.com>
Committed: Mon Apr 8 16:38:10 2013 -0400

----------------------------------------------------------------------
 src/platform.js |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/2f398403/src/platform.js
----------------------------------------------------------------------
diff --git a/src/platform.js b/src/platform.js
index 966a76f..7044fb4 100644
--- a/src/platform.js
+++ b/src/platform.js
@@ -101,6 +101,18 @@ module.exports = function platform(command, targets, callback) {
                             parser.update_project(cfg, function() {
                                 createOverrides(target);
                                 hooks.fire('after_platform_add');
+
+                                // Install all currently installed plugins into this new platform.
+                                var pluginsDir = path.join(projectRoot, 'plugins');
+                                var plugins = fs.readdirSync(pluginsDir);
+                                plugins && plugins.forEach(function(plugin) {
+                                    var cli = path.join(__dirname, '..', 'node_modules', 'plugman', 'plugman.js');
+                                    var cmd = util.format('"%s" --platform "%s" --project "%s" --plugin "%s" --plugins_dir "%s"', cli, target, output, path.basename(plugin), pluginsDir);
+                                    var result = shell.exec(cmd, { silent: true });
+                                    if (result.code > 0) {
+                                        throw new Error('An error occurred while installing the ' + path.basename(plugin) + ' plugin: ' + result.output);
+                                    }
+                                });
                                 end();
                             });
                         });


[31/43] git commit: [CB-3227] Fix missing build script in iOS project.

Posted by an...@apache.org.
[CB-3227] Fix missing build script in iOS project.


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

Branch: refs/heads/master
Commit: bca5ebfdf74806601259fd3936b764f742fb69c6
Parents: 71fb372
Author: Michael Brooks <mi...@michaelbrooks.ca>
Authored: Wed Apr 24 17:20:51 2013 -0700
Committer: Anis Kadri <an...@gmail.com>
Committed: Thu May 9 15:03:57 2013 -0700

----------------------------------------------------------------------
 .gitignore                        |    3 ++
 lib/cordova-android/.gitignore    |   35 --------------------------------
 lib/cordova-blackberry/.gitignore |   26 -----------------------
 lib/cordova-ios/.gitignore        |   12 -----------
 4 files changed, 3 insertions(+), 73 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bca5ebfd/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index b31c8bf..6a593f6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,6 @@ lib/cordova-android/framework/local.properties
 spec/fixtures/*
 .gitcore
 *.jar
+
+# avoid npm pack issues
+.gitignore

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bca5ebfd/lib/cordova-android/.gitignore
----------------------------------------------------------------------
diff --git a/lib/cordova-android/.gitignore b/lib/cordova-android/.gitignore
deleted file mode 100644
index 757a698..0000000
--- a/lib/cordova-android/.gitignore
+++ /dev/null
@@ -1,35 +0,0 @@
-.DS_Store
-default.properties
-gen
-assets/www/cordova.js
-framework/assets/www/.tmp*
-local.properties
-framework/lib
-proguard.cfg
-proguard.cfg
-proguard-project.txt
-framework/bin
-framework/test/org/apache/cordova/*.class
-framework/assets/www/.DS_Store
-framework/assets/www/cordova-*.js
-framework/assets/www/phonegap-*.js
-framework/libs
-test/libs
-example
-./test
-test/bin
-test/assets/www/.tmp*
-tmp/**
-bin/node_modules
-.metadata
-tmp/**/*
-Thumbs.db
-Desktop.ini
-*.tmp
-*.bak
-*.swp
-*.class
-*.jar
-# IntelliJ IDEA files
-*.iml
-.idea

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bca5ebfd/lib/cordova-blackberry/.gitignore
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/.gitignore b/lib/cordova-blackberry/.gitignore
deleted file mode 100644
index a67abe6..0000000
--- a/lib/cordova-blackberry/.gitignore
+++ /dev/null
@@ -1,26 +0,0 @@
-# OS X
-
-.DS_Store
-
-# Eclipse
-
-deliverables/
-.preprocessed/
-
-# Text Editor Tmp
-
-._*
-
-# Generated libraries
-
-build/
-dist/
-bin/node_modules
-bin/templates/project/lib
-example/
-
-# OS X
-
-.DS_Store
-
-tags

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/bca5ebfd/lib/cordova-ios/.gitignore
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/.gitignore b/lib/cordova-ios/.gitignore
deleted file mode 100644
index e0ac686..0000000
--- a/lib/cordova-ios/.gitignore
+++ /dev/null
@@ -1,12 +0,0 @@
-.DS_Store
-.*.sw?
-*.cso
-tmp
-*.mode1v3
-*.pbxuser
-build
-*.xcworkspace
-xcuserdata
-CordovaLib/javascript/cordova-*.js
-CordovaLib/CordovaLibApp/www/cordova.ios.js
-console.log
\ No newline at end of file


[17/43] git commit: Access config.xml from serve. Serve from platform dir only

Posted by an...@apache.org.
Access config.xml from serve. Serve from platform dir only


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

Branch: refs/heads/master
Commit: 6ad6a2652f88cbbfc3f40b5ed6d7883be8e87e61
Parents: 2a5407e
Author: Shravan Narayan <sh...@google.com>
Authored: Wed May 8 14:50:21 2013 -0400
Committer: Shravan Narayan <sh...@google.com>
Committed: Wed May 8 18:17:55 2013 -0400

----------------------------------------------------------------------
 src/metadata/android_parser.js    |    4 ++++
 src/metadata/blackberry_parser.js |    4 ++++
 src/metadata/ios_parser.js        |    7 ++++++-
 src/serve.js                      |   12 +++++++++---
 4 files changed, 23 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6ad6a265/src/metadata/android_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/android_parser.js b/src/metadata/android_parser.js
index be3015c..79c1f2b 100644
--- a/src/metadata/android_parser.js
+++ b/src/metadata/android_parser.js
@@ -130,6 +130,10 @@ module.exports.prototype = {
         return path.join(this.path, '.staging', 'www');
     },
 
+    config_xml:function(){
+        return this.android_config;
+    },
+
     update_www:function() {
         var projectRoot = util.isCordova(this.path);
         var www = util.projectWww(projectRoot);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6ad6a265/src/metadata/blackberry_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/blackberry_parser.js b/src/metadata/blackberry_parser.js
index 16fcbad..97cdd59 100644
--- a/src/metadata/blackberry_parser.js
+++ b/src/metadata/blackberry_parser.js
@@ -94,6 +94,10 @@ module.exports.prototype = {
         return path.join(this.path, '.staging', 'www');
     },
 
+    config_xml:function(){
+        return this.config_path;
+    },
+
     update_www:function() {
         var projectRoot = util.isCordova(this.path);
         var www = util.projectWww(projectRoot);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6ad6a265/src/metadata/ios_parser.js
----------------------------------------------------------------------
diff --git a/src/metadata/ios_parser.js b/src/metadata/ios_parser.js
index 5e83ed3..5c22256 100644
--- a/src/metadata/ios_parser.js
+++ b/src/metadata/ios_parser.js
@@ -55,7 +55,8 @@ module.exports = function ios_parser(project) {
     }
     this.path = project;
     this.pbxproj = path.join(this.xcodeproj, 'project.pbxproj');
-    this.config = new config_parser(path.join(this.cordovaproj, 'config.xml'));
+    this.config_path = path.join(this.cordovaproj, 'config.xml');
+    this.config = new config_parser(this.config_path);
 };
 
 module.exports.check_requirements = function(callback) {
@@ -141,6 +142,10 @@ module.exports.prototype = {
         return path.join(this.path, '.staging', 'www');
     },
 
+    config_xml:function(){
+        return this.config_path;
+    },
+
     update_www:function() {
         var projectRoot = util.isCordova(this.path);
         var www = util.projectWww(projectRoot);

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/6ad6a265/src/serve.js
----------------------------------------------------------------------
diff --git a/src/serve.js b/src/serve.js
index 771f64f..2829847 100644
--- a/src/serve.js
+++ b/src/serve.js
@@ -30,11 +30,11 @@ var cordova_util = require('./util'),
     url = require("url");
 
 
-function launch_server(www, platform_www, port) {
+function launch_server(www, platform_www, config_xml_path, port) {
     port = port || 8000;
 
     // Searches these directories in order looking for the requested file.
-    var searchPath = [www, platform_www];
+    var searchPath = [platform_www];
 
     var server = http.createServer(function(request, response) {
         var uri = url.parse(request.url).pathname;
@@ -48,6 +48,9 @@ function launch_server(www, platform_www, port) {
             }
 
             var filename = path.join(searchPath[pathIndex], uri);
+            if(uri === "/config.xml"){
+                filename = config_xml_path;
+            }
 
             fs.exists(filename, function(exists) {
                 if(!exists) {
@@ -82,7 +85,7 @@ module.exports = function serve (platform, port) {
     var returnValue = {};
 
     module.exports.config(platform, port, function (config) {
-        returnValue.server = launch_server(config.paths[0], config.paths[1], port);
+        returnValue.server = launch_server(config.paths[0], config.paths[1], config.config_xml_path, port);
     });
 
     // Hack for testing despite its async nature.
@@ -113,6 +116,8 @@ module.exports.config = function (platform, port, callback) {
 
     var result = {
         paths: [],
+        // Config file path
+        config_xml_path : "",
         // Default port is 8000 if not given. This is also the default of the Python module.
         port: port || 8000
     };
@@ -137,6 +142,7 @@ module.exports.config = function (platform, port, callback) {
     // Update the related platform project from the config
     parser.update_project(cfg, function() {
         result.paths.push(parser.www_dir());
+        result.config_xml_path = parser.config_xml();
         callback(result);
     });
 }


[19/43] 2.6.0rc1 used for libs now. Bumped npm version to 2.6.0. added androids local.properties to gitignore.

Posted by an...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLibTests/CDVLocalStorageTests.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/CDVLocalStorageTests.m b/lib/cordova-ios/CordovaLibTests/CDVLocalStorageTests.m
index 64a1435..675f5ea 100644
--- a/lib/cordova-ios/CordovaLibTests/CDVLocalStorageTests.m
+++ b/lib/cordova-ios/CordovaLibTests/CDVLocalStorageTests.m
@@ -71,9 +71,9 @@
     CDVLocalStorage* localStorage = [self localStorage];
 
     [self waitForConditionName:@"shouldBackup" block:^{
-            [self evalJs:@"localStorage.setItem('foo', 'bar')"];
-            return [localStorage shouldBackup];
-        }];
+        [self evalJs:@"localStorage.setItem('foo', 'bar')"];
+        return [localStorage shouldBackup];
+    }];
     [localStorage backup:[CDVInvokedUrlCommand new]];
     STAssertFalse([localStorage shouldBackup], @"Should have backed up.");
 
@@ -92,8 +92,8 @@
 - (void)testVerifyAndFixDatabaseLocations_noChangeRequired
 {
     NSString* const kBundlePath = @"/bpath";
-    id fakeFileManager = [CDVFakeFileManager managerWithFileExistsBlock:^(NSString * path) {
-            STFail (@"fileExists called.");
+    id fakeFileManager = [CDVFakeFileManager managerWithFileExistsBlock:^(NSString* path) {
+            STFail(@"fileExists called.");
             return NO;
         }];
     NSMutableDictionary* appPlistDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
@@ -104,13 +104,13 @@
                                                                           bundlePath:kBundlePath
                                                                          fileManager:fakeFileManager];
 
-    STAssertFalse (modified, @"Should not have applied fix.");
+    STAssertFalse(modified, @"Should not have applied fix.");
 }
 
 - (void)testVerifyAndFixDatabaseLocations_changeRequired1
 {
     NSString* const kBundlePath = @"/bpath";
-    id fakeFileManager = [CDVFakeFileManager managerWithFileExistsBlock:^(NSString * path) {
+    id fakeFileManager = [CDVFakeFileManager managerWithFileExistsBlock:^(NSString* path) {
             return YES;
         }];
     NSMutableDictionary* appPlistDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
@@ -120,15 +120,15 @@
                                                                           bundlePath:kBundlePath
                                                                          fileManager:fakeFileManager];
 
-    STAssertTrue (modified, @"Should have applied fix.");
+    STAssertTrue(modified, @"Should have applied fix.");
     NSString* newPath = [appPlistDict objectForKey:@"WebKitLocalStorageDatabasePathPreferenceKey"];
-    STAssertTrue ([@"/bpath/Library/Caches" isEqualToString:newPath], nil);
+    STAssertTrue([@"/bpath/Library/Caches" isEqualToString: newPath], nil);
 }
 
 - (void)testVerifyAndFixDatabaseLocations_changeRequired2
 {
     NSString* const kBundlePath = @"/bpath";
-    id fakeFileManager = [CDVFakeFileManager managerWithFileExistsBlock:^(NSString * path) {
+    id fakeFileManager = [CDVFakeFileManager managerWithFileExistsBlock:^(NSString* path) {
             return NO;
         }];
     NSMutableDictionary* appPlistDict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
@@ -138,9 +138,9 @@
                                                                           bundlePath:kBundlePath
                                                                          fileManager:fakeFileManager];
 
-    STAssertTrue (modified, @"Should have applied fix.");
+    STAssertTrue(modified, @"Should have applied fix.");
     NSString* newPath = [appPlistDict objectForKey:@"WebDatabaseDirectory"];
-    STAssertTrue ([@"/bpath/Library/WebKit" isEqualToString:newPath], nil);
+    STAssertTrue([@"/bpath/Library/WebKit" isEqualToString: newPath], nil);
 }
 
 @end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLibTests/CDVUserAgentTest.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/CDVUserAgentTest.m b/lib/cordova-ios/CordovaLibTests/CDVUserAgentTest.m
index dcbf30a..98659f8 100644
--- a/lib/cordova-ios/CordovaLibTests/CDVUserAgentTest.m
+++ b/lib/cordova-ios/CordovaLibTests/CDVUserAgentTest.m
@@ -82,8 +82,8 @@
 
     NSString* getUserAgentCode = @"navigator.userAgent";
     [self waitForConditionName:@"getting user-agents" block:^{
-            return (BOOL)(rootVc.vc1.webView.request != nil && rootVc.vc2.webView.request != nil);
-        }];
+        return (BOOL)(rootVc.vc1.webView.request != nil && rootVc.vc2.webView.request != nil);
+    }];
     NSString* ua1 = [rootVc.vc1.webView stringByEvaluatingJavaScriptFromString:getUserAgentCode];
     NSString* ua2 = [rootVc.vc2.webView stringByEvaluatingJavaScriptFromString:getUserAgentCode];
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLibTests/CDVWebViewTest.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/CDVWebViewTest.m b/lib/cordova-ios/CordovaLibTests/CDVWebViewTest.m
index c0cb173..e22992a 100644
--- a/lib/cordova-ios/CordovaLibTests/CDVWebViewTest.m
+++ b/lib/cordova-ios/CordovaLibTests/CDVWebViewTest.m
@@ -110,8 +110,8 @@
 - (void)waitForPageLoad
 {
     [self waitForConditionName:@"PageLoad" block:^{
-            return [@"true" isEqualToString:[self evalJs:@"window.pageIsLoaded"]];
-        }];
+        return [@"true" isEqualToString :[self evalJs:@"window.pageIsLoaded"]];
+    }];
 }
 
 - (NSString*)evalJs:(NSString*)code

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml b/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml
index 512bd1f..5610e5e 100644
--- a/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml
+++ b/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml
@@ -2,9 +2,9 @@
 <widget>
     <preference name="KeyboardDisplayRequiresUserAction" value="true" />
     <preference name="SuppressesIncrementalRendering" value="false" />
-    <preference name="UIWebViewBounce" value="true" />
+    <preference name="DisallowOverscroll" value="false" />
     <preference name="TopActivityIndicator" value="gray" />
-    <preference name="EnableLocation" value="false" />
+    <preference name="EnableLocation" value="false" /><!-- DEPRECATED -->
     <preference name="EnableViewportScale" value="false" />
     <preference name="AutoHideSplashScreen" value="true" />
     <preference name="ShowSplashScreenSpinner" value="true" />
@@ -13,6 +13,8 @@
     <preference name="MediaPlaybackRequiresUserAction" value="false" />
     <preference name="AllowInlineMediaPlayback" value="false" />
     <preference name="BackupWebStorage" value="cloud" />
+    <preference name="HideKeyboardFormAccessoryBar" value="false" />
+    <preference name="KeyboardShrinksView" value="false" />
 
     <plugins>
         <plugin name="LocalStorage" value="CDVLocalStorage" />

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj b/lib/cordova-ios/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
index f29ac11..219eb53 100644
--- a/lib/cordova-ios/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
+++ b/lib/cordova-ios/CordovaLibTests/CordovaTests.xcodeproj/project.pbxproj
@@ -41,6 +41,8 @@
 		68A32D7D141030E4006B237C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 686357AE141002F100DF4CF2 /* CoreGraphics.framework */; };
 		68A32D7E141030EB006B237C /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 686357AA141002F100DF4CF2 /* UIKit.framework */; };
 		68A32D7F141030F3006B237C /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 686357AC141002F100DF4CF2 /* Foundation.framework */; };
+		8220B5C216D541BD00EC3921 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8220B5C116D541BD00EC3921 /* AssetsLibrary.framework */; };
+		8220B5C616D542F500EC3921 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8220B5C116D541BD00EC3921 /* AssetsLibrary.framework */; };
 		EB3B34E9161B5532003DBE7D /* libCordova.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EB3B34E6161B5454003DBE7D /* libCordova.a */; };
 		EB89634A15FE66EA00E12277 /* CDVInvokedUrlCommandTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB89634915FE66EA00E12277 /* CDVInvokedUrlCommandTests.m */; };
 		EB96677216ADBCF500D86CDF /* CDVUserAgentTest.m in Sources */ = {isa = PBXBuildFile; fileRef = EB96677116ADBCF500D86CDF /* CDVUserAgentTest.m */; };
@@ -104,6 +106,7 @@
 		686357D414100AF200DF4CF2 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
 		686357DC14100B1600DF4CF2 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
 		68A32D7414103017006B237C /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; };
+		8220B5C116D541BD00EC3921 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; };
 		EB37018115D18B2D00BEBC43 /* CordovaLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CordovaLib.xcodeproj; path = ../CordovaLib/CordovaLib.xcodeproj; sourceTree = "<group>"; };
 		EB89634915FE66EA00E12277 /* CDVInvokedUrlCommandTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVInvokedUrlCommandTests.m; sourceTree = "<group>"; };
 		EB96677116ADBCF500D86CDF /* CDVUserAgentTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVUserAgentTest.m; sourceTree = "<group>"; };
@@ -120,6 +123,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				EB3B34E9161B5532003DBE7D /* libCordova.a in Frameworks */,
+				8220B5C216D541BD00EC3921 /* AssetsLibrary.framework in Frameworks */,
 				30F8AE0C152125B6006625B3 /* MobileCoreServices.framework in Frameworks */,
 				30F8AE0515212587006625B3 /* AddressBook.framework in Frameworks */,
 				30F8AE0615212587006625B3 /* AddressBookUI.framework in Frameworks */,
@@ -139,6 +143,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				68A32D7514103017006B237C /* AddressBook.framework in Frameworks */,
+				8220B5C616D542F500EC3921 /* AssetsLibrary.framework in Frameworks */,
 				68A32D7614103078006B237C /* CoreMedia.framework in Frameworks */,
 				68A32D7714103082006B237C /* AudioToolbox.framework in Frameworks */,
 				68A32D781410308B006B237C /* AVFoundation.framework in Frameworks */,
@@ -181,6 +186,7 @@
 			isa = PBXGroup;
 			children = (
 				68A32D7414103017006B237C /* AddressBook.framework */,
+				8220B5C116D541BD00EC3921 /* AssetsLibrary.framework */,
 				686357DC14100B1600DF4CF2 /* CoreMedia.framework */,
 				686357CE14100ADA00DF4CF2 /* AudioToolbox.framework */,
 				686357CF14100ADB00DF4CF2 /* AVFoundation.framework */,

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLibTests/ExifTests.h
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/ExifTests.h b/lib/cordova-ios/CordovaLibTests/ExifTests.h
new file mode 100644
index 0000000..b46241b
--- /dev/null
+++ b/lib/cordova-ios/CordovaLibTests/ExifTests.h
@@ -0,0 +1,27 @@
+//
+//  ExifTestTests.h
+//  ExifTestTests
+//
+//  Created by Lorin Beer on 2013-03-18.
+//
+//
+
+#import <SenTestingKit/SenTestingKit.h>
+
+#import "../ExifTest/CDVJpegHeaderWriter.h"
+
+#define ARC4RANDOM_MAX 0x100000000
+
+@interface ExifTestTests : SenTestCase {
+    CDVJpegHeaderWriter * testHeaderWriter;
+    NSNumber * testErrorThreshhold;
+}
+
+- (void) testContinuedFractionWithUInt;
+- (void) testContinuedFractionWithUFloat;
+- (void) testContinuedFractionsWorstCase;
+- (void) testFormatHexFromDecimal;
+- (void) testFormatNumberWithLeadingZeroes;
+- (void) testUnsignedRationalToString;
+- (void) testSignedRationalToString;
+@end
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/CordovaLibTests/ExifTests.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/CordovaLibTests/ExifTests.m b/lib/cordova-ios/CordovaLibTests/ExifTests.m
new file mode 100644
index 0000000..960ac95
--- /dev/null
+++ b/lib/cordova-ios/CordovaLibTests/ExifTests.m
@@ -0,0 +1,155 @@
+//
+//  ExifTestTests.m
+//  ExifTestTests
+//
+//  Created by Lorin Beer on 2013-03-18.
+//
+//
+
+#import <SenTestingKit/SenTestingKit.h>
+
+#import "ExifTestTests.h"
+#import "../ExifTest/CDVJpegHeaderWriter.m"
+
+
+@implementation ExifTestTests
+
+- (void)setUp
+{
+    [super setUp];
+    testHeaderWriter = [[CDVJpegHeaderWriter alloc] init];
+    testErrorThreshhold = [NSNumber numberWithDouble: 0.000001];
+    NSLog(@"%x", ~10+1);
+    
+    
+}
+
+- (void)tearDown
+{
+    // Tear-down code here.
+    
+    [super tearDown];
+}
+
+//==================================================================================================
+// rational approximation of decimal by continued fraction tests
+//==================================================================================================
+
+// tests continued fraction with random int
+- (void)testContinuedFractionWithUInt {
+    NSLog(@"Continued Fraction Test with random int value, numerator should be generated value, denominator should be 1");
+    NSNumber * numerator = @0;
+    NSNumber * denominator = @0;
+    NSNumber * testValue = [NSNumber numberWithInt: abs(arc4random())];
+    [testHeaderWriter decimalToUnsignedRational: testValue
+                  withResultNumerator: &numerator
+                withResultDenominator: &denominator];
+    STAssertEquals([numerator intValue],
+                   [testValue intValue],
+                   @"Numerator did not match");
+    STAssertEquals([denominator intValue],
+                   1,
+                   @"denominator was not one");
+}
+
+// tests continued fraction with random float
+- (void)testContinuedFractionWithUFloat {
+    NSLog(@"Continued Fraction Test with random double value, resulting fraction should be within acceptable error threshhold");
+    NSNumber * threshhold = @0.1;
+    NSNumber * numerator = @0;
+    NSNumber * denominator = @0;
+    NSLog(@"%f",((double)arc4random() / ARC4RANDOM_MAX) * 100.0f);
+    NSNumber * testValue = [NSNumber numberWithDouble:
+                                ((double)arc4random() / ARC4RANDOM_MAX) * 100.0f];
+
+    [testHeaderWriter decimalToUnsignedRational: testValue
+                            withResultNumerator: &numerator
+                          withResultDenominator: &denominator];
+    NSLog(@"%lf, %lf",[testValue doubleValue], [numerator doubleValue]/[denominator doubleValue]);
+
+    STAssertEqualsWithAccuracy([testValue doubleValue],
+                               [numerator doubleValue]/[denominator doubleValue],
+                               [threshhold doubleValue],
+                               @"rational approximation did not meet acceptable error threshhold");
+    
+}
+
+// tests continued fraction in sqrt(2) worst case
+- (void)testContinuedFractionsWorstCase {
+    NSLog(@"Continued Fraction Test with provable worst case ~sqrt(2), resulting fraction should be within acceptable error threshhold");
+    NSNumber * threshhold = @0.1;
+    NSNumber * numerator = @0;
+    NSNumber * denominator = @0;
+    NSNumber * testValue = [NSNumber numberWithDouble: sqrt(2)];
+    [testHeaderWriter decimalToUnsignedRational: testValue
+                            withResultNumerator: &numerator
+                          withResultDenominator: &denominator];
+    STAssertEqualsWithAccuracy([testValue doubleValue],
+                               [numerator doubleValue]/[denominator doubleValue],
+                               [threshhold doubleValue],
+                               @"rational approximation did not meet acceptable error threshhold");
+}
+
+// tests format hex from a decimal
+- (void) testFormatHexFromDecimal {
+    NSNumber * testValue = @1;
+    NSNumber * testPlaces = @8;
+    NSString * result = nil;
+    result = [testHeaderWriter formattedHexStringFromDecimalNumber: testValue
+                                                        withPlaces: testPlaces];
+    // assert not nil
+    STAssertNotNil(result, @"nil renturned from formattedHexStringFromDecimalNumber");
+    // assert correct number of places
+    STAssertEquals([result length], [testPlaces unsignedIntegerValue],
+                   @"returned string to wrong number of places. Should be = %i Was = %i",
+                   [testPlaces intValue],
+                   [result length]);
+    // assert correct hex representation
+    STAssertTrueNoThrow([result isEqualToString:@"00000001"], @"result should be equal to @00000001");
+
+}
+
+// tests format number string with leading zeroes
+- (void) testFormatNumberWithLeadingZeroes {
+    NSString * result = nil;
+    NSNumber * testValue = @8769; // Exif SubIFD Offset Tag
+    NSNumber * testPlaces = @6;
+    result = [testHeaderWriter formatNumberWithLeadingZeroes: testValue
+                                                  withPlaces: testPlaces];
+    STAssertNotNil(result, @"nil renturned from formattedHexStringFromDecimalNumber");
+    STAssertEquals([result length],
+                   [testPlaces unsignedIntegerValue],
+                   @"returned string to wrong number of places. Should be = %i Was = %i",
+                   [testPlaces intValue],
+                   [result length]);
+    // assert correct hex representation
+    STAssertTrueNoThrow([result isEqualToString:@"008769"], @"result was = %@ should be = @008769", result);
+}
+
+- (void) testUnsignedRationalToString {
+    NSString * result = nil;
+    NSNumber * numerator = @1;
+    NSNumber * denominator = @10;
+    result = [testHeaderWriter formatRationalWithNumerator: numerator
+                                           withDenominator: denominator
+                                                  asSigned: FALSE];
+    NSLog(result);
+    STAssertNotNil(result, @"nil returned from testUnsignedRationalToString");
+    STAssertTrueNoThrow([result length]==16, @"returned string with wrong length. Exif rationals are 8 bytes, string has %ld bytes",[result length]/2);
+    STAssertTrueNoThrow([result isEqualToString:@"000000010000000a"], @"result was = %@ should be = @0000000100000010", result);
+}
+
+- (void) testSignedRationalToString {
+    NSString * result = nil;
+    NSNumber * numerator = @-1;
+    NSNumber * denominator = @-10;
+    result = [testHeaderWriter formatRationalWithNumerator: numerator
+                                           withDenominator: denominator
+                                                  asSigned: TRUE];
+    NSLog(result);
+    STAssertNotNil(result, @"nil returned from testSignedRationalToString");
+    STAssertTrueNoThrow([result length]==16, @"returned string with wrong length. Exif rationals are 8 bytes, string has %ld bytes",[result length]/2);
+    STAssertTrueNoThrow([result isEqualToString:@"fffffffffffffff6"], @"result was = %@ should be = @000000FF000000F6", result);
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/RELEASENOTES.md
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/RELEASENOTES.md b/lib/cordova-ios/RELEASENOTES.md
index 843493e..e83c647 100644
--- a/lib/cordova-ios/RELEASENOTES.md
+++ b/lib/cordova-ios/RELEASENOTES.md
@@ -22,7 +22,65 @@
  
  Cordova is a static library that enables developers to include the Cordova API in their iOS application projects easily, and also create new Cordova-based iOS application projects through the command-line.
 
- ### 2.5.0 (20130301) ###
+### 2.6.0 (20130401) ###
+
+* [CB-1547] Scope notifications to WebViews
+* [CB-2461] Distinguish sub-frame from top-level loads in InAppBrowser.
+* [CB-2523] Add setting to shrink webview when keyboard pops up
+* [CB-2220] Fix splashscreen origin when status bar is present
+* [CB-2220] Size the splash screen in the same way as the launch image
+* [CB-2389] Fix page load detection for late-loaded iframes
+* [CB-2220] Fix splash screen positioning when image is the size of device
+* [CB-2631] Fix crash when bad url given to FT.upload
+* [CB-2652] Make FileReader.readAs*() functions run on a background thread
+* [CB-2633] Add FileReader.readAsBinaryString()
+* [CB-2308] Correctly delegate to CDVInAppBrowser webView:didFailLoadWithError
+* [CB-2308] [ios] Report errors when InAppBrowser fails to load page
+* [CB-2527] Update iPad splash images to correct sizes
+* [CB-1452] Media position incorrect after being set beyond duration
+* [CB-2436] Wrong splashscreen is displayed when UILaunchImageFile is set
+* [CB-2634] Copy www fails w spaces in filenames
+* [CB-2618] xcode build from Network Drive Fails
+* [CB-2638] Fix iOS project warnings on Retina imgs
+* [CB-2491] Deprecate current Connection cell setting
+* [CB-2674] Add prompt to Notification API for iOS
+* [CB-2691] Splashscreen should block user interaction
+* [CB-2502] Fixing CDVViewController.commandDelegate property declaration
+* [CB-1933] Changed button labels to an array.
+* [CB-1688] Added a camera direction option.
+* [CB-2732] Only set camera device when allowed.
+* [CB-2530] [CB-2239] Multipart plugin result
+* [CB-2605] icon-72@2x.png not included in xcode project template
+* [CB-2545] Deprecate "EnableLocation" Project Setting - use the "onload" attribute of the <plugin> element
+* [CB-2384] Add new iOS Project Setting to suppress the form accessory bar above the keyboard
+* [CB-2195] Remove deprecated - iOS - BackupWebStorage Cordova.plist property change from boolean to string
+* [CB-2194] Remove deprecated - iOS - CDVCommandDelegate registerPlugin method
+* [CB-2699] Bug in dynamic loading of a plugin at CDVViewController's registerPlugin method
+* [CB-2384] Re-fix - Add new iOS Project Setting to suppress the form accessory bar above the keyboard
+* [CB-2759] Update www/ Application for iOS
+* [CB-2672] InAppBrowserBug fixed (not reporting actual URL after redirect)
+* [CB-861] Header support for FileTransfer download
+* Add a define that turns on logging of exec() bridge
+* Sort preferences in project template.
+* Add KeyboardShrinksView preference to project template
+* Revert accidentaly change in PluginResult that broke threading.
+* Remove NSLogs accidentally checked in.
+* Use noCopy versions of NSString init in Base64 code.
+* Add an associatedObject field to CDVPluginResult.
+* Uncrustified with v0.60 of the tool (up from 0.59).
+* Make sure version of uncrustify is correct in the pre-commit hook
+* Remove some unnecessary argument checks in CDVNotification
+* Implement readAsArrayBuffer
+* Changed UIWebViewBounce to DisallowOverscroll.
+* Retain cycle fix
+* Fixed static analyzer issues.
+* Interim .js for [CB-52] FileTransfer Basic Auth
+* Added KeyboardShrinksView preference to CordovaLibTest config.xml
+* Added \__CORDOVA_IOS\__ macro
+
+< br />
+
+### 2.5.0 (20130301) ###
 
 * [CB-2395] Fix CDVViewController UserAgent lock
 * [CB-2207] Use a custom script for www/ copying.
@@ -76,7 +134,7 @@
 
 <br />
 
- ### 2.4.0 (20130205) ###
+### 2.4.0 (20130205) ###
 
 * Make cordova_plist_to_config_xml able to handle binary plist files
 * Ran splashscreen images through ImageOptim.
@@ -129,7 +187,7 @@
 
 <br />
 
- ### 2.3.0 (20130107) ###
+### 2.3.0 (20130107) ###
 
 * [CB-1550] iOS build, debug, emulate scripts should check xcode version
 * [CB-1669] Issue an error when media.startRecord() is failing.
@@ -191,7 +249,7 @@
 
 <br />
 
- ### 2.2.0 (20121031) ###
+### 2.2.0 (20121031) ###
 
 * [CB-622] FileTransfer interface should provide progress monitoring
 * [CB-622] Progress events for downloads

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/bin/templates/project/__TESTING__.xcodeproj/project.pbxproj
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__.xcodeproj/project.pbxproj b/lib/cordova-ios/bin/templates/project/__TESTING__.xcodeproj/project.pbxproj
index 1d9c170..f5ed342 100755
--- a/lib/cordova-ios/bin/templates/project/__TESTING__.xcodeproj/project.pbxproj
+++ b/lib/cordova-ios/bin/templates/project/__TESTING__.xcodeproj/project.pbxproj
@@ -40,6 +40,7 @@
 		30A0434814DC770100060A13 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 30A0434314DC770100060A13 /* Localizable.strings */; };
 		30A0434914DC770100060A13 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 30A0434614DC770100060A13 /* Localizable.strings */; };
 		30E5649213A7FCAF007403D8 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30E5649113A7FCAF007403D8 /* CoreMedia.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+		30FC414916E50CA1004E6F35 /* icon-72@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 30FC414816E50CA1004E6F35 /* icon-72@2x.png */; };
 		5B1594DD16A7569C00FEF299 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5B1594DC16A7569C00FEF299 /* AssetsLibrary.framework */; };
 		D4A0D8761607E02300AEF8BB /* Default-568h@2x~iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = D4A0D8751607E02300AEF8BB /* Default-568h@2x~iphone.png */; };
 		F840E1F1165FE0F500CFE078 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = F840E1F0165FE0F500CFE078 /* config.xml */; };
@@ -100,6 +101,7 @@
 		30A0434414DC770100060A13 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = Localizable.strings; sourceTree = "<group>"; };
 		30A0434714DC770100060A13 /* se */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = se; path = Localizable.strings; sourceTree = "<group>"; };
 		30E5649113A7FCAF007403D8 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
+		30FC414816E50CA1004E6F35 /* icon-72@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon-72@2x.png"; sourceTree = "<group>"; };
 		32CA4F630368D1EE00C91783 /* __TESTING__-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "__TESTING__-Prefix.pch"; sourceTree = "<group>"; };
 		5B1594DC16A7569C00FEF299 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; };
 		8D1107310486CEB800E47090 /* __TESTING__-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "__TESTING__-Info.plist"; path = "../__TESTING__-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = "<group>"; };
@@ -254,6 +256,7 @@
 		308D052D1370CCF300D202BF /* icons */ = {
 			isa = PBXGroup;
 			children = (
+				30FC414816E50CA1004E6F35 /* icon-72@2x.png */,
 				308D052E1370CCF300D202BF /* icon-72.png */,
 				308D052F1370CCF300D202BF /* icon.png */,
 				308D05301370CCF300D202BF /* icon@2x.png */,
@@ -382,6 +385,7 @@
 				3088BBC1154F3926009F9C59 /* Default@2x~iphone.png in Resources */,
 				3088BBC2154F3926009F9C59 /* Default~iphone.png in Resources */,
 				D4A0D8761607E02300AEF8BB /* Default-568h@2x~iphone.png in Resources */,
+				30FC414916E50CA1004E6F35 /* icon-72@2x.png in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -400,7 +404,7 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "SRC_DIR=\"www\"\nDST_DIR=\"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/www\"\nCOPY_HIDDEN=\n\nif [[ ! -e \"$SRC_DIR\" ]]; then\n  echo \"Path does not exist: $SRC_DIR\"\n  exit 1\nfi\n\nif [[ -n $COPY_HIDDEN ]]; then\n  alias do_find='find \"$SRC_DIR\"'\nelse\n  alias do_find='find \"$SRC_DIR\" -name \".*\" -prune -o'\nfi\n\ntime (\n# Code signing files must be removed or else there are\n# resource signing errors.\nrm -rf \"$DST_DIR\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/_CodeSignature\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/PkgInfo\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/embedded.mobileprovision\"\n\n# Directories\nfor p in $(do_find -type d -print); do\n  subpath=\"${p#$SRC_DIR}\"\n  mkdir \"$DST_DIR$subpath\" || exit 1\ndone\n\n# Symlinks\nfor p in $(do_find -type l -print); do\n  subpath=\"${p#$SRC_DIR}\"\n  cp -a \"$SRC_DIR$subpath\" \"$DST_DIR$subpath\" || exit 2\ndone\n\n# Files\nfor p in $(do_find -type f -print); do\n 
  subpath=\"${p#$SRC_DIR}\"\n  if ! ln \"$SRC_DIR$subpath\" \"$DST_DIR$subpath\"; then\n    cp -a \"$SRC_DIR$subpath\" \"$DST_DIR$subpath\" || exit 3\n  fi\ndone\n\n)";
+			shellScript = "SRC_DIR=\"www\"\nDST_DIR=\"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/www\"\nCOPY_HIDDEN=\nORIG_IFS=$IFS\nIFS=$(echo -en \"\\n\\b\")\n\nif [[ ! -e \"$SRC_DIR\" ]]; then\n  echo \"Path does not exist: $SRC_DIR\"\n  exit 1\nfi\n\nif [[ -n $COPY_HIDDEN ]]; then\n  alias do_find='find \"$SRC_DIR\"'\nelse\n  alias do_find='find \"$SRC_DIR\" -name \".*\" -prune -o'\nfi\n\ntime (\n# Code signing files must be removed or else there are\n# resource signing errors.\nrm -rf \"$DST_DIR\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/_CodeSignature\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/PkgInfo\" \\\n       \"$BUILT_PRODUCTS_DIR/$FULL_PRODUCT_NAME/embedded.mobileprovision\"\n\n# Directories\nfor p in $(do_find -type d -print); do\n  subpath=\"${p#$SRC_DIR}\"\n  mkdir \"$DST_DIR$subpath\" || exit 1\ndone\n\n# Symlinks\nfor p in $(do_find -type l -print); do\n  subpath=\"${p#$SRC_DIR}\"\n  rsync -a \"$SRC_DIR$subpath\" \"$DST_DIR$subpath\" || exit 2\ndone\n\n# Fi
 les\nfor p in $(do_find -type f -print); do\n  subpath=\"${p#$SRC_DIR}\"\n  if ! ln \"$SRC_DIR$subpath\" \"$DST_DIR$subpath\" 2>/dev/null; then\n    rsync -a \"$SRC_DIR$subpath\" \"$DST_DIR$subpath\" || exit 3\n  fi\ndone\n\n)\nIFS=$ORIG_IFS";
 		};
 /* End PBXShellScriptBuildPhase section */
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m b/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
index 5c05ac8..623ad8e 100644
--- a/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
+++ b/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
@@ -45,11 +45,7 @@
 
     int cacheSizeMemory = 8 * 1024 * 1024; // 8MB
     int cacheSizeDisk = 32 * 1024 * 1024; // 32MB
-#if __has_feature(objc_arc)
-        NSURLCache* sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"];
-#else
-        NSURLCache* sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"] autorelease];
-#endif
+    NSURLCache* sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"] autorelease];
     [NSURLCache setSharedURLCache:sharedCache];
 
     self = [super init];
@@ -65,18 +61,10 @@
 {
     CGRect screenBounds = [[UIScreen mainScreen] bounds];
 
-#if __has_feature(objc_arc)
-        self.window = [[UIWindow alloc] initWithFrame:screenBounds];
-#else
-        self.window = [[[UIWindow alloc] initWithFrame:screenBounds] autorelease];
-#endif
+    self.window = [[[UIWindow alloc] initWithFrame:screenBounds] autorelease];
     self.window.autoresizesSubviews = YES;
 
-#if __has_feature(objc_arc)
-        self.viewController = [[MainViewController alloc] init];
-#else
-        self.viewController = [[[MainViewController alloc] init] autorelease];
-#endif
+    self.viewController = [[[MainViewController alloc] init] autorelease];
     self.viewController.useSplashScreen = YES;
 
     // Set your app's start page by setting the <content src='foo.html' /> tag in config.xml.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-568h@2x~iphone.png
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-568h@2x~iphone.png b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-568h@2x~iphone.png
index d14b55b..10ed683 100644
Binary files a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-568h@2x~iphone.png and b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-568h@2x~iphone.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape@2x~ipad.png
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape@2x~ipad.png b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape@2x~ipad.png
index 72eb605..9f1e14f 100644
Binary files a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape@2x~ipad.png and b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape@2x~ipad.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape~ipad.png
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape~ipad.png b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape~ipad.png
index 30e8587..93a8d74 100644
Binary files a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape~ipad.png and b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Landscape~ipad.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait@2x~ipad.png
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait@2x~ipad.png b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait@2x~ipad.png
index 435bbec..6d1c5d3 100644
Binary files a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait@2x~ipad.png and b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait@2x~ipad.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait~ipad.png
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait~ipad.png b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait~ipad.png
index 5e9786a..30e0a3d 100644
Binary files a/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait~ipad.png and b/lib/cordova-ios/bin/templates/project/__TESTING__/Resources/splash/Default-Portrait~ipad.png differ

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml b/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml
index 64e7163..8889726 100644
--- a/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml
+++ b/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml
@@ -20,19 +20,21 @@
 #
 -->
 <widget>
-    <preference name="KeyboardDisplayRequiresUserAction" value="true" />
-    <preference name="SuppressesIncrementalRendering" value="false" />
-    <preference name="UIWebViewBounce" value="true" />
-    <preference name="TopActivityIndicator" value="gray" />
-    <preference name="EnableLocation" value="false" />
-    <preference name="EnableViewportScale" value="false" />
+    <preference name="AllowInlineMediaPlayback" value="false" />
     <preference name="AutoHideSplashScreen" value="true" />
-    <preference name="ShowSplashScreenSpinner" value="true" />
+    <preference name="BackupWebStorage" value="cloud" />
+    <preference name="DisallowOverscroll" value="false" />
+    <preference name="EnableLocation" value="false" /><!-- DEPRECATED -->
+    <preference name="EnableViewportScale" value="false" />
     <preference name="FadeSplashScreen" value="true" />
     <preference name="FadeSplashScreenDuration" value=".25" />
+    <preference name="HideKeyboardFormAccessoryBar" value="false" />
+    <preference name="KeyboardDisplayRequiresUserAction" value="true" />
+    <preference name="KeyboardShrinksView" value="false" />
     <preference name="MediaPlaybackRequiresUserAction" value="false" />
-    <preference name="AllowInlineMediaPlayback" value="false" />
-    <preference name="BackupWebStorage" value="cloud" />
+    <preference name="ShowSplashScreenSpinner" value="true" />
+    <preference name="SuppressesIncrementalRendering" value="false" />
+    <preference name="TopActivityIndicator" value="gray" />
 
     <content src="index.html" />
 

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/bin/templates/project/www/index.html
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/bin/templates/project/www/index.html b/lib/cordova-ios/bin/templates/project/www/index.html
index 6374050..8bc9055 100644
--- a/lib/cordova-ios/bin/templates/project/www/index.html
+++ b/lib/cordova-ios/bin/templates/project/www/index.html
@@ -19,7 +19,7 @@
 -->
 <html>
     <head>
-        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+        <meta charset="utf-8" />
         <meta name="format-detection" content="telephone=no" />
         <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" />

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/guides/Cordova Plugin Upgrade Guide.md
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/guides/Cordova Plugin Upgrade Guide.md b/lib/cordova-ios/guides/Cordova Plugin Upgrade Guide.md
index 869e4f4..7a03bc4 100644
--- a/lib/cordova-ios/guides/Cordova Plugin Upgrade Guide.md	
+++ b/lib/cordova-ios/guides/Cordova Plugin Upgrade Guide.md	
@@ -22,6 +22,12 @@
 
 This document is for developers who need to upgrade their Cordova  plugins to a newer Cordova version. Starting with Cordova 1.5.0, some classes have been renamed, which will require the plugin to be upgraded. Make sure your project itself has been upgraded using the [Cordova iOS Upgrading Guide](http://cordova.apache.org/docs/en/edge/guide_upgrading_ios_index.md.html#Upgrading%20Cordova%20iOS) document.
 
+## Upgrading older Cordova plugins to 2.6.0 ##
+
+1. **Install** Cordova 2.6.0
+2. Follow the **"Upgrading older Cordova plugins to 2.5.0"** section, if necessary
+3. The **registerPlugin** method of the **commandDelegate** property of plugin, which was deprecated, has been **removed**. Use the **registerPlugin** method directly from the **viewController** property of the plugin.
+
 ## Upgrading older Cordova plugins to 2.5.0 ##
 
 1. **Install** Cordova 2.5.0

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/lib/cordova-ios/hooks/pre-commit
----------------------------------------------------------------------
diff --git a/lib/cordova-ios/hooks/pre-commit b/lib/cordova-ios/hooks/pre-commit
index 7a420c9..80550f1 100755
--- a/lib/cordova-ios/hooks/pre-commit
+++ b/lib/cordova-ios/hooks/pre-commit
@@ -20,6 +20,12 @@
 
 # Redirect output to stderr.
 exec 1>&2
+test $SKIP_UNCRUSTIFY && exit 0
+
+if [[ "$(uncrustify --version | cut -d' ' -f2)" != 0.60 ]]; then
+  echo "Please install version 0.60 of uncrustify."
+  exit 1
+fi
 
 RET=0
 files=$(bin/uncrustify.sh --filter $(git diff --cached --name-only))

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/1ed1ee2d/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index fc7f0b4..207849c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "cordova",
-  "version": "2.5.5",
+  "version": "2.6.0",
   "preferGlobal": "true",
   "description": "Cordova command line interface tool",
   "main": "cordova",