2.5.0rc1 (2.5.0 in package.json). Removed old test related to webworks scripts. Updated lbiraries to 2.5.0rc1. Added a VERSION file.
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..aa0822f
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+2.5.0rc1
diff --git a/lib/cordova-android/README.md b/lib/cordova-android/README.md
index cf7e83f..5d2f7de 100755
--- a/lib/cordova-android/README.md
+++ b/lib/cordova-android/README.md
@@ -5,7 +5,7 @@
 projects to be built for the Android Platform. Cordova based applications are,
 at the core, applications written with web technology: HTML, CSS and JavaScript. 
 
-Apache Cordova is a project at The Apache Software Foundation (ASF).
+[Apache Cordova](http://cordova.io) is a project at The Apache Software Foundation (ASF).
 
 
 Requires
@@ -23,7 +23,7 @@
 Building
 ---
 
-To create your cordova.jar, copy the commons codec:
+To create your `cordova.jar` file, copy the commons codec:
 
     mv commons-codec-1.7.jar framework/libs
 
diff --git a/lib/cordova-android/VERSION b/lib/cordova-android/VERSION
index 197c4d5..aa0822f 100644
--- a/lib/cordova-android/VERSION
+++ b/lib/cordova-android/VERSION
@@ -1 +1 @@
-2.4.0
+2.5.0rc1
diff --git a/lib/cordova-android/bin/create b/lib/cordova-android/bin/create
index c92acb4..ea214ac 100755
--- a/lib/cordova-android/bin/create
+++ b/lib/cordova-android/bin/create
@@ -98,6 +98,13 @@
 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
diff --git a/lib/cordova-android/bin/templates/cordova/appinfo.jar b/lib/cordova-android/bin/templates/cordova/appinfo.jar
index 743a8d6..1a088c5 100644
--- a/lib/cordova-android/bin/templates/cordova/appinfo.jar
+++ b/lib/cordova-android/bin/templates/cordova/appinfo.jar
Binary files differ
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 a6a5ff3..bc06b24 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.4.0.js"></script>
+        <script type="text/javascript" src="cordova-2.5.0rc1.js"></script>
         <script type="text/javascript" src="js/index.js"></script>
         <script type="text/javascript">
             app.initialize();
diff --git a/lib/cordova-android/framework/assets/js/cordova.android.js b/lib/cordova-android/framework/assets/js/cordova.android.js
index 1eb1ca8..19c9281 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 ac725f6ae0bd655789771e2a40b8d60cb4c8c221
+// commit 521bbd64ed729ca76b6646d25bb01b76ee8a54b5
 
-// File generated at :: Mon Feb 04 2013 10:59:03 GMT-0800 (PST)
+// File generated at :: Wed Feb 20 2013 13:49:25 GMT-0800 (PST)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -399,6 +399,7 @@
 }
 
 function clobber(obj, key, value) {
+    exports.replaceHookForTesting(obj, key);
     obj[key] = value;
     // Getters can only be overridden by getters.
     if (obj[key] !== value) {
@@ -482,19 +483,18 @@
     }
 }
 
-module.exports = {
-    buildIntoButDoNotClobber: function(objects, target) {
-        include(target, objects, false, false);
-    },
-    buildIntoAndClobber: function(objects, target) {
-        include(target, objects, true, false);
-    },
-    buildIntoAndMerge: function(objects, target) {
-        include(target, objects, true, true);
-    },
-    recursiveMerge: recursiveMerge,
-    assignOrWrapInDeprecateGetter: assignOrWrapInDeprecateGetter
+exports.buildIntoButDoNotClobber = function(objects, target) {
+    include(target, objects, false, false);
 };
+exports.buildIntoAndClobber = function(objects, target) {
+    include(target, objects, true, false);
+};
+exports.buildIntoAndMerge = function(objects, target) {
+    include(target, objects, true, true);
+};
+exports.recursiveMerge = recursiveMerge;
+exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
+exports.replaceHookForTesting = function() {};
 
 });
 
@@ -774,176 +774,6 @@
 };
 });
 
-// file: lib/common/common.js
-define("cordova/common", function(require, exports, module) {
-
-module.exports = {
-    defaults: {
-        cordova: {
-            path: 'cordova',
-            children: {
-                exec: {
-                    path: 'cordova/exec'
-                },
-                logger: {
-                    path: 'cordova/plugin/logger'
-                }
-            }
-        },
-        Cordova: {
-            children: {
-                exec: {
-                    path: 'cordova/exec'
-                }
-            }
-        },
-        open : {
-            path: 'cordova/plugin/InAppBrowser'
-        },
-        navigator: {
-            children: {
-                notification: {
-                    path: 'cordova/plugin/notification'
-                },
-                accelerometer: {
-                    path: 'cordova/plugin/accelerometer'
-                },
-                battery: {
-                    path: 'cordova/plugin/battery'
-                },
-                camera:{
-                    path: 'cordova/plugin/Camera'
-                },
-                compass:{
-                    path: 'cordova/plugin/compass'
-                },
-                contacts: {
-                    path: 'cordova/plugin/contacts'
-                },
-                device:{
-                    children:{
-                        capture: {
-                            path: 'cordova/plugin/capture'
-                        }
-                    }
-                },
-                geolocation: {
-                    path: 'cordova/plugin/geolocation'
-                },
-                globalization: {
-                    path: 'cordova/plugin/globalization'
-                },
-                network: {
-                    children: {
-                        connection: {
-                            path: 'cordova/plugin/network',
-                            deprecated: 'navigator.network.connection is deprecated. Use navigator.connection instead.'
-                        }
-                    }
-                },
-                splashscreen: {
-                    path: 'cordova/plugin/splashscreen'
-                }
-            }
-        },
-        Acceleration: {
-            path: 'cordova/plugin/Acceleration'
-        },
-        Camera:{
-            path: 'cordova/plugin/CameraConstants'
-        },
-        CameraPopoverOptions: {
-            path: 'cordova/plugin/CameraPopoverOptions'
-        },
-        CaptureError: {
-            path: 'cordova/plugin/CaptureError'
-        },
-        CaptureAudioOptions:{
-            path: 'cordova/plugin/CaptureAudioOptions'
-        },
-        CaptureImageOptions: {
-            path: 'cordova/plugin/CaptureImageOptions'
-        },
-        CaptureVideoOptions: {
-            path: 'cordova/plugin/CaptureVideoOptions'
-        },
-        CompassHeading:{
-            path: 'cordova/plugin/CompassHeading'
-        },
-        CompassError:{
-            path: 'cordova/plugin/CompassError'
-        },
-        ConfigurationData: {
-            path: 'cordova/plugin/ConfigurationData'
-        },
-        Connection: {
-            path: 'cordova/plugin/Connection'
-        },
-        Contact: {
-            path: 'cordova/plugin/Contact'
-        },
-        ContactAddress: {
-            path: 'cordova/plugin/ContactAddress'
-        },
-        ContactError: {
-            path: 'cordova/plugin/ContactError'
-        },
-        ContactField: {
-            path: 'cordova/plugin/ContactField'
-        },
-        ContactFindOptions: {
-            path: 'cordova/plugin/ContactFindOptions'
-        },
-        ContactName: {
-            path: 'cordova/plugin/ContactName'
-        },
-        ContactOrganization: {
-            path: 'cordova/plugin/ContactOrganization'
-        },
-        Coordinates: {
-            path: 'cordova/plugin/Coordinates'
-        },
-        device: {
-            path: 'cordova/plugin/device'
-        },
-        GlobalizationError: {
-            path: 'cordova/plugin/GlobalizationError'
-        },
-        Media: {
-            path: 'cordova/plugin/Media'
-        },
-        MediaError: {
-            path: 'cordova/plugin/MediaError'
-        },
-        MediaFile: {
-            path: 'cordova/plugin/MediaFile'
-        },
-        MediaFileData:{
-            path: 'cordova/plugin/MediaFileData'
-        },
-        Position: {
-            path: 'cordova/plugin/Position'
-        },
-        PositionError: {
-            path: 'cordova/plugin/PositionError'
-        },
-        ProgressEvent: {
-            path: 'cordova/plugin/ProgressEvent'
-        }
-    },
-    clobbers: {
-        navigator: {
-            children: {
-                connection: {
-                    path: 'cordova/plugin/network'
-                }
-            }
-        }
-    }
-};
-
-});
-
 // file: lib/android/exec.js
 define("cordova/exec", function(require, exports, module) {
 
@@ -1222,9 +1052,9 @@
     var parts = symbolPath.split('.');
     var cur = context;
     for (var i = 0, part; part = parts[i]; ++i) {
-        cur[part] = cur[part] || {};
+        cur = cur[part] = cur[part] || {};
     }
-    return cur[parts[i-1]];
+    return cur;
 }
 
 exports.mapModules = function(context) {
@@ -1246,7 +1076,7 @@
         if (strategy == 'm' && target) {
             builder.recursiveMerge(target, module);
         } else if ((strategy == 'd' && !target) || (strategy != 'd')) {
-            if (target) {
+            if (!(symbolPath in origSymbols)) {
                 origSymbols[symbolPath] = target;
             }
             builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
@@ -1292,6 +1122,8 @@
             modulemapper = require('cordova/modulemapper');
 
         modulemapper.loadMatchingModules(/cordova.*\/symbols$/);
+        modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');
+
         modulemapper.mapModules(window);
 
         // Inject a listener for the backbutton on the document.
@@ -1306,88 +1138,11 @@
         cordova.addDocumentEventHandler('menubutton');
         cordova.addDocumentEventHandler('searchbutton');
 
-        // Figure out if we need to shim-in localStorage and WebSQL
-        // support from the native side.
-        var storage = require('cordova/plugin/android/storage');
-
-        // First patch WebSQL if necessary
-        if (typeof window.openDatabase == 'undefined') {
-            // Not defined, create an openDatabase function for all to use!
-            window.openDatabase = storage.openDatabase;
-        } else {
-            // Defined, but some Android devices will throw a SECURITY_ERR -
-            // so we wrap the whole thing in a try-catch and shim in our own
-            // if the device has Android bug 16175.
-            var originalOpenDatabase = window.openDatabase;
-            window.openDatabase = function(name, version, desc, size) {
-                var db = null;
-                try {
-                    db = originalOpenDatabase(name, version, desc, size);
-                }
-                catch (ex) {
-                    if (ex.code === 18) {
-                        db = null;
-                    } else {
-                        throw ex;
-                    }
-                }
-
-                if (db === null) {
-                    return storage.openDatabase(name, version, desc, size);
-                }
-                else {
-                    return db;
-                }
-
-            };
-        }
-
-        // Patch localStorage if necessary
-        if (typeof window.localStorage == 'undefined' || window.localStorage === null) {
-            window.localStorage = new storage.CupcakeLocalStorage();
-        }
-
         // Let native code know we are all done on the JS side.
         // Native code will then un-hide the WebView.
         channel.join(function() {
             exec(null, null, "App", "show", []);
         }, [channel.onCordovaReady]);
-    },
-    clobbers: {
-        navigator: {
-            children: {
-                app:{
-                    path: "cordova/plugin/android/app"
-                }
-            }
-        },
-        File: { // exists natively on Android WebView, override
-            path: "cordova/plugin/File"
-        },
-        FileReader: { // exists natively on Android WebView, override
-            path: "cordova/plugin/FileReader"
-        },
-        FileError: { //exists natively on Android WebView on Android 4.x
-            path: "cordova/plugin/FileError"
-        },
-        MediaError: { // exists natively on Android WebView on Android 4.x
-            path: "cordova/plugin/MediaError"
-        },
-        open: {
-            path: "cordova/plugin/InAppBrowser"
-        }
-    },
-    merges: {
-        device: {
-            path: 'cordova/plugin/android/device'
-        },
-        navigator: {
-            children: {
-                notification: {
-                    path: 'cordova/plugin/android/notification'
-                }
-            }
-        }
     }
 };
 
@@ -1621,9 +1376,9 @@
 define("cordova/plugin/CompassHeading", function(require, exports, module) {
 
 var CompassHeading = function(magneticHeading, trueHeading, headingAccuracy, timestamp) {
-  this.magneticHeading = magneticHeading || null;
-  this.trueHeading = trueHeading || null;
-  this.headingAccuracy = headingAccuracy || null;
+  this.magneticHeading = magneticHeading;
+  this.trueHeading = trueHeading;
+  this.headingAccuracy = headingAccuracy;
   this.timestamp = timestamp || new Date().getTime();
 };
 
@@ -2996,11 +2751,12 @@
  * FileTransferError
  * @constructor
  */
-var FileTransferError = function(code, source, target, status) {
+var FileTransferError = function(code, source, target, status, body) {
     this.code = code || null;
     this.source = source || null;
     this.target = target || null;
     this.http_status = status || null;
+    this.body = body || null;
 };
 
 FileTransferError.FILE_NOT_FOUND_ERR = 1;
@@ -3404,8 +3160,6 @@
     return iab;
 };
 
-//Export the original open so it can be used if needed
-module.exports._orig = window.open;
 
 });
 
@@ -3976,6 +3730,17 @@
 
 });
 
+// file: lib/common/plugin/accelerometer/symbols.js
+define("cordova/plugin/accelerometer/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Acceleration', 'Acceleration');
+modulemapper.defaults('cordova/plugin/accelerometer', 'navigator.accelerometer');
+
+});
+
 // file: lib/android/plugin/android/app.js
 define("cordova/plugin/android/app", function(require, exports, module) {
 
@@ -4480,102 +4245,59 @@
     return db;
 };
 
-/**
- * For browsers with no localStorage we emulate it with SQLite. Follows the w3c api.
- * TODO: Do similar for sessionStorage.
- * @constructor
- */
-var CupcakeLocalStorage = function() {
-    channel.waitForInitialization("cupcakeStorage");
-
-    try {
-
-      this.db = openDatabase('localStorage', '1.0', 'localStorage', 2621440);
-      var storage = {};
-      this.length = 0;
-      function setLength (length) {
-        this.length = length;
-        localStorage.length = length;
-      }
-      this.db.transaction(
-        function (transaction) {
-            var i;
-          transaction.executeSql('CREATE TABLE IF NOT EXISTS storage (id NVARCHAR(40) PRIMARY KEY, body NVARCHAR(255))');
-          transaction.executeSql('SELECT * FROM storage', [], function(tx, result) {
-            for(var i = 0; i < result.rows.length; i++) {
-              storage[result.rows.item(i).id] =  result.rows.item(i).body;
-            }
-            setLength(result.rows.length);
-            channel.initializationComplete("cupcakeStorage");
-          });
-
-        },
-        function (err) {
-          utils.alert(err.message);
-        }
-      );
-      this.setItem = function(key, val) {
-        if (typeof(storage[key])=='undefined') {
-          this.length++;
-        }
-        storage[key] = val;
-        this.db.transaction(
-          function (transaction) {
-            transaction.executeSql('CREATE TABLE IF NOT EXISTS storage (id NVARCHAR(40) PRIMARY KEY, body NVARCHAR(255))');
-            transaction.executeSql('REPLACE INTO storage (id, body) values(?,?)', [key,val]);
-          }
-        );
-      };
-      this.getItem = function(key) {
-        return storage[key];
-      };
-      this.removeItem = function(key) {
-        delete storage[key];
-        this.length--;
-        this.db.transaction(
-          function (transaction) {
-            transaction.executeSql('CREATE TABLE IF NOT EXISTS storage (id NVARCHAR(40) PRIMARY KEY, body NVARCHAR(255))');
-            transaction.executeSql('DELETE FROM storage where id=?', [key]);
-          }
-        );
-      };
-      this.clear = function() {
-        storage = {};
-        this.length = 0;
-        this.db.transaction(
-          function (transaction) {
-            transaction.executeSql('CREATE TABLE IF NOT EXISTS storage (id NVARCHAR(40) PRIMARY KEY, body NVARCHAR(255))');
-            transaction.executeSql('DELETE FROM storage', []);
-          }
-        );
-      };
-      this.key = function(index) {
-        var i = 0;
-        for (var j in storage) {
-          if (i==index) {
-            return j;
-          } else {
-            i++;
-          }
-        }
-        return null;
-      };
-
-    } catch(e) {
-          utils.alert("Database error "+e+".");
-        return;
-    }
-};
 
 module.exports = {
   openDatabase:DroidDB_openDatabase,
-  CupcakeLocalStorage:CupcakeLocalStorage,
   failQuery:failQuery,
   completeQuery:completeQuery
 };
 
 });
 
+// file: lib/android/plugin/android/storage/openDatabase.js
+define("cordova/plugin/android/storage/openDatabase", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper'),
+    storage = require('cordova/plugin/android/storage');
+
+var originalOpenDatabase = modulemapper.getOriginalSymbol(window, 'openDatabase');
+
+module.exports = function(name, version, desc, size) {
+    // First patch WebSQL if necessary
+    if (!originalOpenDatabase) {
+        // Not defined, create an openDatabase function for all to use!
+        return storage.openDatabase.apply(this, arguments);
+    }
+
+    // Defined, but some Android devices will throw a SECURITY_ERR -
+    // so we wrap the whole thing in a try-catch and shim in our own
+    // if the device has Android bug 16175.
+    try {
+        return originalOpenDatabase(name, version, desc, size);
+    } catch (ex) {
+        if (ex.code !== 18) {
+            throw ex;
+        }
+    }
+    return storage.openDatabase(name, version, desc, size);
+};
+
+
+
+});
+
+// file: lib/android/plugin/android/storage/symbols.js
+define("cordova/plugin/android/storage/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/android/storage/openDatabase', 'openDatabase');
+
+
+});
+
 // file: lib/common/plugin/battery.js
 define("cordova/plugin/battery", function(require, exports, module) {
 
@@ -4660,6 +4382,28 @@
 
 });
 
+// file: lib/common/plugin/battery/symbols.js
+define("cordova/plugin/battery/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/battery', 'navigator.battery');
+
+});
+
+// file: lib/common/plugin/camera/symbols.js
+define("cordova/plugin/camera/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Camera', 'navigator.camera');
+modulemapper.defaults('cordova/plugin/CameraConstants', 'Camera');
+modulemapper.defaults('cordova/plugin/CameraPopoverOptions', 'CameraPopoverOptions');
+
+});
+
 // file: lib/common/plugin/capture.js
 define("cordova/plugin/capture", function(require, exports, module) {
 
@@ -4738,6 +4482,22 @@
 
 });
 
+// file: lib/common/plugin/capture/symbols.js
+define("cordova/plugin/capture/symbols", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/CaptureError', 'CaptureError');
+modulemapper.clobbers('cordova/plugin/CaptureAudioOptions', 'CaptureAudioOptions');
+modulemapper.clobbers('cordova/plugin/CaptureImageOptions', 'CaptureImageOptions');
+modulemapper.clobbers('cordova/plugin/CaptureVideoOptions', 'CaptureVideoOptions');
+modulemapper.clobbers('cordova/plugin/ConfigurationData', 'ConfigurationData');
+modulemapper.clobbers('cordova/plugin/MediaFile', 'MediaFile');
+modulemapper.clobbers('cordova/plugin/MediaFileData', 'MediaFileData');
+modulemapper.clobbers('cordova/plugin/capture', 'navigator.device.capture');
+
+});
+
 // file: lib/common/plugin/compass.js
 define("cordova/plugin/compass", function(require, exports, module) {
 
@@ -4825,6 +4585,18 @@
 
 });
 
+// file: lib/common/plugin/compass/symbols.js
+define("cordova/plugin/compass/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/CompassHeading', 'CompassHeading');
+modulemapper.clobbers('cordova/plugin/CompassError', 'CompassError');
+modulemapper.clobbers('cordova/plugin/compass', 'navigator.compass');
+
+});
+
 // file: lib/common/plugin/console-via-logger.js
 define("cordova/plugin/console-via-logger", function(require, exports, module) {
 
@@ -5058,6 +4830,23 @@
 
 });
 
+// file: lib/common/plugin/contacts/symbols.js
+define("cordova/plugin/contacts/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/contacts', 'navigator.contacts');
+modulemapper.clobbers('cordova/plugin/Contact', 'Contact');
+modulemapper.clobbers('cordova/plugin/ContactAddress', 'ContactAddress');
+modulemapper.clobbers('cordova/plugin/ContactError', 'ContactError');
+modulemapper.clobbers('cordova/plugin/ContactField', 'ContactField');
+modulemapper.clobbers('cordova/plugin/ContactFindOptions', 'ContactFindOptions');
+modulemapper.clobbers('cordova/plugin/ContactName', 'ContactName');
+modulemapper.clobbers('cordova/plugin/ContactOrganization', 'ContactOrganization');
+
+});
+
 // file: lib/common/plugin/device.js
 define("cordova/plugin/device", function(require, exports, module) {
 
@@ -5117,6 +4906,17 @@
 
 });
 
+// file: lib/android/plugin/device/symbols.js
+define("cordova/plugin/device/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/device', 'device');
+modulemapper.merges('cordova/plugin/android/device', 'device');
+
+});
+
 // file: lib/common/plugin/echo.js
 define("cordova/plugin/echo", function(require, exports, module) {
 
@@ -5163,20 +4963,30 @@
     exportFunc('cordova/plugin/FileError', 'FileError');
     exportFunc('cordova/plugin/FileReader', 'FileReader');
     exportFunc('cordova/plugin/FileSystem', 'FileSystem');
-    exportFunc('cordova/plugin/FileTransfer', 'FileTransfer');
-    exportFunc('cordova/plugin/FileTransferError', 'FileTransferError');
     exportFunc('cordova/plugin/FileUploadOptions', 'FileUploadOptions');
     exportFunc('cordova/plugin/FileUploadResult', 'FileUploadResult');
     exportFunc('cordova/plugin/FileWriter', 'FileWriter');
     exportFunc('cordova/plugin/Flags', 'Flags');
     exportFunc('cordova/plugin/LocalFileSystem', 'LocalFileSystem');
     exportFunc('cordova/plugin/Metadata', 'Metadata');
+    exportFunc('cordova/plugin/ProgressEvent', 'ProgressEvent');
     exportFunc('cordova/plugin/requestFileSystem', 'requestFileSystem');
     exportFunc('cordova/plugin/resolveLocalFileSystemURI', 'resolveLocalFileSystemURI');
 };
 
 });
 
+// file: lib/common/plugin/filetransfer/symbols.js
+define("cordova/plugin/filetransfer/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/FileTransfer', 'FileTransfer');
+modulemapper.clobbers('cordova/plugin/FileTransferError', 'FileTransferError');
+
+});
+
 // file: lib/common/plugin/geolocation.js
 define("cordova/plugin/geolocation", function(require, exports, module) {
 
@@ -5373,6 +5183,19 @@
 
 });
 
+// file: lib/common/plugin/geolocation/symbols.js
+define("cordova/plugin/geolocation/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/geolocation', 'navigator.geolocation');
+modulemapper.clobbers('cordova/plugin/PositionError', 'PositionError');
+modulemapper.clobbers('cordova/plugin/Position', 'Position');
+modulemapper.clobbers('cordova/plugin/Coordinates', 'Coordinates');
+
+});
+
 // file: lib/common/plugin/globalization.js
 define("cordova/plugin/globalization", function(require, exports, module) {
 
@@ -5749,6 +5572,27 @@
 
 });
 
+// file: lib/common/plugin/globalization/symbols.js
+define("cordova/plugin/globalization/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/globalization', 'navigator.globalization');
+modulemapper.clobbers('cordova/plugin/GlobalizationError', 'GlobalizationError');
+
+});
+
+// file: lib/android/plugin/inappbrowser/symbols.js
+define("cordova/plugin/inappbrowser/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/InAppBrowser', 'open');
+
+});
+
 // file: lib/common/plugin/logger.js
 define("cordova/plugin/logger", function(require, exports, module) {
 
@@ -5977,6 +5821,27 @@
 
 });
 
+// file: lib/common/plugin/logger/symbols.js
+define("cordova/plugin/logger/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/logger', 'cordova.logger');
+
+});
+
+// file: lib/android/plugin/media/symbols.js
+define("cordova/plugin/media/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Media', 'Media');
+modulemapper.clobbers('cordova/plugin/MediaError', 'MediaError');
+
+});
+
 // file: lib/common/plugin/network.js
 define("cordova/plugin/network", function(require, exports, module) {
 
@@ -6049,6 +5914,18 @@
 
 });
 
+// file: lib/common/plugin/networkstatus/symbols.js
+define("cordova/plugin/networkstatus/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/network', 'navigator.network.connection', 'navigator.network.connection is deprecated. Use navigator.connection instead.');
+modulemapper.clobbers('cordova/plugin/network', 'navigator.connection');
+modulemapper.defaults('cordova/plugin/Connection', 'Connection');
+
+});
+
 // file: lib/common/plugin/notification.js
 define("cordova/plugin/notification", function(require, exports, module) {
 
@@ -6111,6 +5988,17 @@
 
 });
 
+// file: lib/android/plugin/notification/symbols.js
+define("cordova/plugin/notification/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/notification', 'navigator.notification');
+modulemapper.merges('cordova/plugin/android/notification', 'navigator.notification');
+
+});
+
 // file: lib/common/plugin/requestFileSystem.js
 define("cordova/plugin/requestFileSystem", function(require, exports, module) {
 
@@ -6224,6 +6112,29 @@
 
 });
 
+// file: lib/common/plugin/splashscreen/symbols.js
+define("cordova/plugin/splashscreen/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/splashscreen', 'navigator.splashscreen');
+
+});
+
+// file: lib/common/symbols.js
+define("cordova/symbols", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+// Use merges here in case others symbols files depend on this running first,
+// but fail to declare the dependency with a require().
+modulemapper.merges('cordova', 'cordova');
+modulemapper.clobbers('cordova/exec', 'cordova.exec');
+modulemapper.clobbers('cordova/exec', 'Cordova.exec');
+
+});
+
 // file: lib/common/utils.js
 define("cordova/utils", function(require, exports, module) {
 
@@ -6492,14 +6403,8 @@
                  */
                 channel.join(function() {
                     var builder = require('cordova/builder'),
-                        base = require('cordova/common'),
                         platform = require('cordova/platform');
 
-                    // Drop the common globals into the window object, but be nice and don't overwrite anything.
-                    builder.buildIntoButDoNotClobber(base.defaults, context);
-                    builder.buildIntoAndClobber(base.clobbers, context);
-                    builder.buildIntoAndMerge(base.merges, context);
-
                     builder.buildIntoButDoNotClobber(platform.defaults, context);
                     builder.buildIntoAndClobber(platform.clobbers, context);
                     builder.buildIntoAndMerge(platform.merges, context);
diff --git a/lib/cordova-android/framework/assets/www/index.html b/lib/cordova-android/framework/assets/www/index.html
index ffcaf02..209e0b5 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.4.0.js"></script>
+    <script src="cordova-2.5.0rc1.js"></script>
   </head>
   <body>
 
diff --git a/lib/cordova-android/framework/project.properties b/lib/cordova-android/framework/project.properties
index 2f39d91..d556741 100644
--- a/lib/cordova-android/framework/project.properties
+++ b/lib/cordova-android/framework/project.properties
@@ -10,7 +10,7 @@
 # Indicates whether an apk should be generated for each density.
 split.density=false
 # Project target.
-target=android-17
+target=Google Inc.:Google APIs:17
 apk-configurations=
 renderscript.opt.level=O0
 android.library=true
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 3012ee3..aec0def 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CameraLauncher.java
@@ -58,6 +58,7 @@
 
     private static final int DATA_URL = 0;              // Return base64 encoded string
     private static final int FILE_URI = 1;              // Return file uri (content://media/external/images/media/2 for Android)
+    private static final int NATIVE_URI = 2;			// On Android, this is the same as FILE_URI
 
     private static final int PHOTOLIBRARY = 0;          // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
     private static final int CAMERA = 1;                // Take picture from camera
@@ -310,7 +311,7 @@
                     }
 
                     // If sending filename back
-                    else if (destType == FILE_URI) {
+                    else if (destType == FILE_URI || destType == NATIVE_URI) {
                         if (!this.saveToPhotoAlbum) {
                             uri = Uri.fromFile(new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), System.currentTimeMillis() + ".jpg"));
                         } else {
@@ -388,9 +389,9 @@
                 }
                 else {
                     // This is a special case to just return the path as no scaling,
-                    // rotating or compression needs to be done
+                    // rotating, nor compressing needs to be done
                     if (this.targetHeight == -1 && this.targetWidth == -1 &&
-                            this.mQuality == 100 && destType == FILE_URI && !this.correctOrientation) {
+                            (destType == FILE_URI || destType == NATIVE_URI) && !this.correctOrientation) {
                         this.callbackContext.success(uri.toString());
                     } else {
                         // Get the path to the image. Makes loading so much easier.
@@ -434,7 +435,7 @@
                         }
 
                         // If sending filename back
-                        else if (destType == FILE_URI) {
+                        else if (destType == FILE_URI || destType == NATIVE_URI) {
                             // Do we need to scale the returned file
                             if (this.targetHeight > 0 && this.targetWidth > 0) {
                                 try {
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/ContactAccessor.java b/lib/cordova-android/framework/src/org/apache/cordova/ContactAccessor.java
index 44bed23..04b4342 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/ContactAccessor.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/ContactAccessor.java
@@ -18,7 +18,6 @@
 
 import java.util.HashMap;
 
-import android.content.Context;
 import android.util.Log;
 import android.webkit.WebView;
 
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/ContactAccessorSdk5.java b/lib/cordova-android/framework/src/org/apache/cordova/ContactAccessorSdk5.java
index 3d81648..47336c0 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/ContactAccessorSdk5.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/ContactAccessorSdk5.java
@@ -860,8 +860,7 @@
             im.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Im._ID)));
             im.put("pref", false); // Android does not store pref attribute
             im.put("value", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA)));
-            String type = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Im.PROTOCOL));
-            im.put("type", getImType(new Integer(type).intValue()));
+            im.put("type", getImType(cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Im.PROTOCOL))));
         } catch (JSONException e) {
             Log.e(LOG_TAG, e.getMessage(), e);
         }
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 4b30894..e650781 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/CordovaChromeClient.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CordovaChromeClient.java
@@ -24,12 +24,10 @@
 import org.json.JSONException;
 
 import android.annotation.TargetApi;
-import android.app.Activity;
 import android.app.AlertDialog;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.net.Uri;
-import android.util.Log;
 import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.View;
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 44c9299..4731adb 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebView.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/CordovaWebView.java
@@ -27,7 +27,6 @@
 
 import org.apache.cordova.Config;
 import org.apache.cordova.api.CordovaInterface;
-import org.apache.cordova.api.CordovaPlugin;
 import org.apache.cordova.api.LOG;
 import org.apache.cordova.api.PluginManager;
 import org.apache.cordova.api.PluginResult;
@@ -263,6 +262,7 @@
         settings.setDatabaseEnabled(true);
         String databasePath = this.cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
         settings.setDatabasePath(databasePath);
+        settings.setGeolocationDatabasePath(databasePath);
 
         // Enable DOM storage
         settings.setDomStorageEnabled(true);
@@ -270,6 +270,13 @@
         // Enable built-in geolocation
         settings.setGeolocationEnabled(true);
         
+        // Enable AppCache
+        // Fix for CB-2282
+        settings.setAppCacheMaxSize(5 * 1048576);
+        String pathToCache = this.cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
+        settings.setAppCachePath(pathToCache);
+        settings.setAppCacheEnabled(true);
+        
         // Fix for CB-1405
         // Google issue 4641
         this.updateUserAgentString();
@@ -554,15 +561,14 @@
 
         // 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()) {
+        if (super.canGoBack() && this.useBrowserHistory) {
             printBackForwardList();
             super.goBack();
             
             return true;
         }
-
         // If our managed history has prev url
-        if (this.urls.size() > 1 && !this.useBrowserHistory) {
+        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);
@@ -578,10 +584,10 @@
      * @return
      */
     public boolean canGoBack() {
-        if (super.canGoBack()) {
+        if (super.canGoBack() && this.useBrowserHistory) {
             return true;
         }
-        if (this.urls.size() > 1) {
+        else if (this.urls.size() > 1) {
             return true;
         }
         return false;
@@ -749,7 +755,9 @@
                     // If not, then invoke default behaviour
                     else {
                         //this.activityState = ACTIVITY_EXITING;
-                        return false;
+                    	//return false;
+                    	// If they hit back button when app is initializing, app should exit instead of hang until initilazation (CB2-458)
+                    	this.cordova.getActivity().finish();
                     }
                 }
             }
@@ -847,7 +855,8 @@
     public void handleDestroy()
     {
         // Send destroy event to JavaScript
-        this.loadUrl("javascript:try{cordova.require('cordova/channel').onDestroy.fire();}catch(e){console.log('exception firing destroy event from native');};");
+    	// Since baseUrl is set in loadUrlIntoView, if user hit Back button before loadUrl was called, we'll get an NPE on baseUrl (CB-2458)
+        this.loadUrlIntoView("javascript:try{cordova.require('cordova/channel').onDestroy.fire();}catch(e){console.log('exception firing destroy event from native');};");
 
         // Load blank page so that JavaScript onunload is called
         this.loadUrl("about:blank");
@@ -910,11 +919,14 @@
     {
         WebBackForwardList currentList = this.copyBackForwardList();
         WebHistoryItem item = currentList.getItemAtIndex(0);
-        String url = item.getUrl();
-        String currentUrl = this.getUrl();
-        LOG.d(TAG, "The current URL is: " + currentUrl);
-        LOG.d(TAG, "The URL at item 0 is:" + url);
-        return currentUrl.equals(url);
+        if( item!=null){	// Null-fence in case they haven't called loadUrl yet (CB-2458)
+	        String url = item.getUrl();
+	        String currentUrl = this.getUrl();
+	        LOG.d(TAG, "The current URL is: " + currentUrl);
+	        LOG.d(TAG, "The URL at item 0 is:" + url);
+	        return currentUrl.equals(url);
+        }
+        return false;
     }
 
     public void showCustomView(View view, WebChromeClient.CustomViewCallback callback) {
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 883fc55..cbf49fd 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/Device.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/Device.java
@@ -24,7 +24,6 @@
 import org.apache.cordova.api.CordovaPlugin;
 import org.apache.cordova.api.LOG;
 import org.apache.cordova.api.CordovaInterface;
-import org.apache.cordova.api.PluginResult;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -39,7 +38,7 @@
 public class Device extends CordovaPlugin {
     public static final String TAG = "Device";
 
-    public static String cordovaVersion = "2.4.0";              // Cordova version
+    public static String cordovaVersion = "2.5.0rc1";              // Cordova version
     public static String platform = "Android";                  // Device OS
     public static String uuid;                                  // Device UUID
 
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 ee21eb8..9a7be4e 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/DroidGap.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/DroidGap.java
@@ -51,7 +51,6 @@
 import android.view.Window;
 import android.view.WindowManager;
 import android.webkit.ValueCallback;
-import android.webkit.WebView;
 import android.webkit.WebViewClient;
 import android.widget.LinearLayout;
 
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 a36bb62..48e7102 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/ExposedJsApi.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/ExposedJsApi.java
@@ -20,7 +20,6 @@
 
 import android.webkit.JavascriptInterface;
 import org.apache.cordova.api.PluginManager;
-import org.apache.cordova.api.PluginResult;
 import org.json.JSONException;
 
 /**
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 783a71b..623baf8 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/FileTransfer.java
@@ -20,7 +20,6 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
-import java.io.DataOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -33,6 +32,7 @@
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.net.URLConnection;
 import java.net.URLDecoder;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
@@ -77,6 +77,7 @@
     private static final class RequestContext {
         String source;
         String target;
+        File targetFile;
         CallbackContext callbackContext;
         InputStream currentInputStream;
         OutputStream currentOutputStream;
@@ -200,7 +201,7 @@
             callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
             return;
         }
-        final boolean useHttps = url.getProtocol().toLowerCase().equals("https");
+        final boolean useHttps = url.getProtocol().equals("https");
 
         final RequestContext context = new RequestContext(source, target, callbackContext);
         synchronized (activeRequests) {
@@ -258,7 +259,6 @@
 
                     // Use a post method.
                     conn.setRequestMethod("POST");
-                    conn.setRequestProperty("Connection", "Keep-Alive");
                     conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);
 
                     // Set the cookies on the response
@@ -291,37 +291,35 @@
                         * Store the non-file portions of the multipart data as a string, so that we can add it
                         * to the contentSize, since it is part of the body of the HTTP request.
                         */
-                    String extraParams = "";
+                    StringBuilder beforeData = new StringBuilder();
                     try {
                         for (Iterator<?> iter = params.keys(); iter.hasNext();) {
                             Object key = iter.next();
                             if(!String.valueOf(key).equals("headers"))
                             {
-                              extraParams += LINE_START + BOUNDARY + LINE_END;
-                              extraParams += "Content-Disposition: form-data; name=\"" +  key.toString() + "\";";
-                              extraParams += LINE_END + LINE_END;
-                              extraParams += params.getString(key.toString());
-                              extraParams += LINE_END;
+                              beforeData.append(LINE_START).append(BOUNDARY).append(LINE_END);
+                              beforeData.append("Content-Disposition: form-data; name=\"").append(key.toString()).append('"');
+                              beforeData.append(LINE_END).append(LINE_END);
+                              beforeData.append(params.getString(key.toString()));
+                              beforeData.append(LINE_END);
                             }
                         }
                     } catch (JSONException e) {
                         Log.e(LOG_TAG, e.getMessage(), e);
                     }
 
-                    extraParams += LINE_START + BOUNDARY + LINE_END;
-                    extraParams += "Content-Disposition: form-data; name=\"" + fileKey + "\";" + " filename=\"";
-                    byte[] extraBytes = extraParams.getBytes("UTF-8");
-
-                    String midParams = "\"" + LINE_END + "Content-Type: " + mimeType + LINE_END + LINE_END;
-                    String tailParams = LINE_END + LINE_START + BOUNDARY + LINE_START + LINE_END;
-                    byte[] fileNameBytes = fileName.getBytes("UTF-8");
+                    beforeData.append(LINE_START).append(BOUNDARY).append(LINE_END);
+                    beforeData.append("Content-Disposition: form-data; name=\"").append(fileKey).append("\";");
+                    beforeData.append(" filename=\"").append(fileName).append('"').append(LINE_END);
+                    beforeData.append("Content-Type: ").append(mimeType).append(LINE_END).append(LINE_END);
+                    byte[] beforeDataBytes = beforeData.toString().getBytes("UTF-8");
+                    byte[] tailParamsBytes = (LINE_END + LINE_START + BOUNDARY + LINE_START + LINE_END).getBytes("UTF-8");
 
                     
                     // Get a input stream of the file on the phone
                     InputStream sourceInputStream = getPathFromUri(source);
                     
-                    int stringLength = extraBytes.length + midParams.length() + tailParams.length() + fileNameBytes.length;
-                    Log.d(LOG_TAG, "String Length: " + stringLength);
+                    int stringLength = beforeDataBytes.length + tailParamsBytes.length;
                     if (sourceInputStream instanceof FileInputStream) {
                         fixedLength = (int) ((FileInputStream)sourceInputStream).getChannel().size() + stringLength;
                         progress.setLengthComputable(true);
@@ -333,7 +331,7 @@
                     // It also causes OOM if HTTPS is used, even on newer devices.
                     boolean useChunkedMode = chunkedMode && (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO || useHttps);
                     useChunkedMode = useChunkedMode || (fixedLength == -1);
-                            
+
                     if (useChunkedMode) {
                         conn.setChunkedStreamingMode(MAX_BUFFER_SIZE);
                         // Although setChunkedStreamingMode sets this header, setting it explicitly here works
@@ -343,19 +341,20 @@
                         conn.setFixedLengthStreamingMode(fixedLength);
                     }
 
-                    DataOutputStream dos = null;
+                    conn.connect();
+                    
+                    OutputStream sendStream = null;
                     try {
-                        dos = new DataOutputStream( conn.getOutputStream() );
+                        sendStream = conn.getOutputStream();
                         synchronized (context) {
                             if (context.aborted) {
                                 return;
                             }
-                            context.currentOutputStream = dos;
+                            context.currentOutputStream = sendStream;
                         }
                         //We don't want to change encoding, we just want this to write for all Unicode.
-                        dos.write(extraBytes);
-                        dos.write(fileNameBytes);
-                        dos.writeBytes(midParams);
+                        sendStream.write(beforeDataBytes);
+                        totalBytes += beforeDataBytes.length;
     
                         // create a buffer of maximum size
                         int bytesAvailable = sourceInputStream.available();
@@ -367,9 +366,9 @@
     
                         long prevBytesRead = 0;
                         while (bytesRead > 0) {
-                            totalBytes += bytesRead;
                             result.setBytesSent(totalBytes);
-                            dos.write(buffer, 0, bytesRead);
+                            sendStream.write(buffer, 0, bytesRead);
+                            totalBytes += bytesRead;
                             if (totalBytes > prevBytesRead + 102400) {
                                 prevBytesRead = totalBytes;
                                 Log.d(LOG_TAG, "Uploaded " + totalBytes + " of " + fixedLength + " bytes");
@@ -386,17 +385,21 @@
                         }
     
                         // send multipart form data necessary after file data...
-                        dos.writeBytes(tailParams);
-                        dos.flush();
+                        sendStream.write(tailParamsBytes);
+                        totalBytes += tailParamsBytes.length;
+                        sendStream.flush();
                     } finally {
                         safeClose(sourceInputStream);
-                        safeClose(dos);
+                        safeClose(sendStream);
                     }
                     context.currentOutputStream = null;
+                    Log.d(LOG_TAG, "Sent " + totalBytes + " of " + fixedLength);
 
                     //------------------ read the SERVER RESPONSE
                     String responseString;
                     int responseCode = conn.getResponseCode();
+                    Log.d(LOG_TAG, "response code: " + responseCode);
+                    Log.d(LOG_TAG, "response headers: " + conn.getHeaderFields());
                     InputStream inStream = null;
                     try {
                         inStream = getInputStream(conn);
@@ -407,8 +410,7 @@
                             context.currentInputStream = inStream;
                         }
                         
-    
-                        ByteArrayOutputStream out = new ByteArrayOutputStream();
+                        ByteArrayOutputStream out = new ByteArrayOutputStream(Math.max(1024, conn.getContentLength()));
                         byte[] buffer = new byte[1024];
                         int bytesRead = 0;
                         // write bytes to file
@@ -459,8 +461,6 @@
                             https.setHostnameVerifier(oldHostnameVerifier);
                             https.setSSLSocketFactory(oldSocketFactory);
                         }
-
-                        conn.disconnect();
                     }
                 }                
             }
@@ -476,7 +476,7 @@
         }
     }
 
-    private static InputStream getInputStream(HttpURLConnection conn) throws IOException {
+    private static InputStream getInputStream(URLConnection conn) throws IOException {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
             return new DoneHandlerInputStream(conn.getInputStream());
         }
@@ -527,13 +527,15 @@
         return oldFactory;
     }
 
-    private static JSONObject createFileTransferError(int errorCode, String source, String target, HttpURLConnection connection) {
+    private static JSONObject createFileTransferError(int errorCode, String source, String target, URLConnection connection) {
 
-        Integer httpStatus = null;
+        int httpStatus = 0;
 
         if (connection != null) {
             try {
-                httpStatus = connection.getResponseCode();
+                if (connection instanceof HttpURLConnection) {
+                    httpStatus = ((HttpURLConnection)connection).getResponseCode();
+                }
             } catch (IOException e) {
                 Log.w(LOG_TAG, "Error getting HTTP status code from connection.", e);
             }
@@ -602,7 +604,7 @@
             callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
             return;
         }
-        final boolean useHttps = url.getProtocol().toLowerCase().equals("https");
+        final boolean useHttps = url.getProtocol().equals("https");
 
         if (!Config.isUrlWhiteListed(source)) {
             Log.w(LOG_TAG, "Source URL is not in white list: '" + source + "'");
@@ -622,14 +624,16 @@
                 if (context.aborted) {
                     return;
                 }
-                HttpURLConnection connection = null;
+                URLConnection connection = null;
                 HostnameVerifier oldHostnameVerifier = null;
                 SSLSocketFactory oldSocketFactory = null;
+                File file = null;
+                PluginResult result = null;
 
                 try {
-
+                    file = getFileFromPath(target);
+                    context.targetFile = file;
                     // create needed directories
-                    File file = getFileFromPath(target);
                     file.getParentFile().mkdirs();
         
                     // connect to server
@@ -654,10 +658,12 @@
                     }
                     // Return a standard HTTP connection
                     else {
-                          connection = (HttpURLConnection) url.openConnection();
+                          connection = url.openConnection();
                     }
     
-                    connection.setRequestMethod("GET");
+                    if (connection instanceof HttpURLConnection) {
+                        ((HttpURLConnection)connection).setRequestMethod("GET");
+                    }
     
                     //Add cookie support
                     String cookie = CookieManager.getInstance().getCookie(source);
@@ -715,22 +721,22 @@
                     FileUtils fileUtil = new FileUtils();
                     JSONObject fileEntry = fileUtil.getEntry(file);
                     
-                    context.sendPluginResult(new PluginResult(PluginResult.Status.OK, fileEntry));
+                    result = new PluginResult(PluginResult.Status.OK, fileEntry);
                 } catch (FileNotFoundException e) {
                     JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR, source, target, connection);
                     Log.e(LOG_TAG, error.toString(), e);
-                    context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
+                    result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
                 } catch (IOException e) {
                     JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, connection);
                     Log.e(LOG_TAG, error.toString(), e);
-                    context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
+                    result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
                 } catch (JSONException e) {
                     Log.e(LOG_TAG, e.getMessage(), e);
-                    context.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                    result = new PluginResult(PluginResult.Status.JSON_EXCEPTION);
                 } catch (Throwable e) {
                     JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, connection);
                     Log.e(LOG_TAG, error.toString(), e);
-                    context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
+                    result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
                 } finally {
                     synchronized (activeRequests) {
                         activeRequests.remove(objectId);
@@ -743,9 +749,16 @@
                             https.setHostnameVerifier(oldHostnameVerifier);
                             https.setSSLSocketFactory(oldSocketFactory);
                         }
-    
-                        connection.disconnect();
                     }
+
+                    if (result == null) {
+                        result = new PluginResult(PluginResult.Status.ERROR, createFileTransferError(CONNECTION_ERR, source, target, connection));
+                    }
+                    // Remove incomplete download.
+                    if (result.getStatus() != PluginResult.Status.OK.ordinal() && file != null) {
+                        file.delete();
+                    }
+                    context.sendPluginResult(result);
                 }
             }
         });
@@ -808,6 +821,10 @@
             context = activeRequests.remove(objectId);
         }
         if (context != null) {
+            File file = context.targetFile;
+            if (file != null) {
+                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);
             synchronized (context) {
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 554458b..b461b02 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/FileUtils.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/FileUtils.java
@@ -43,7 +43,6 @@
 import android.net.Uri;
 import android.os.Environment;
 import android.provider.MediaStore;
-import android.util.Log;
 import android.webkit.MimeTypeMap;
 
 //import android.app.Activity;
@@ -89,7 +88,7 @@
      * Executes the request and returns whether the action was valid.
      *
      * @param action 		The action to execute.
-     * @param args 		JSONArry of arguments for the plugin.
+     * @param args 		JSONArray of arguments for the plugin.
      * @param callbackContext	The callback context used when calling back into JavaScript.
      * @return 			True if the action was valid, false otherwise.
      */
@@ -238,7 +237,7 @@
      * @param filePath the path to check
      */
     private void notifyDelete(String filePath) {
-        String newFilePath = stripFileProtocol(filePath);
+        String newFilePath = getRealPathFromURI(Uri.parse(filePath), cordova);
         try {
             this.cordova.getActivity().getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                 MediaStore.Images.Media.DATA + " = ?",
@@ -342,18 +341,18 @@
      * @throws InvalidModificationException
      * @throws EncodingException
      * @throws JSONException
-     * @throws FileExistsException 
+     * @throws FileExistsException
      */
     private JSONObject transferTo(String fileName, String newParent, String newName, boolean move) throws JSONException, NoModificationAllowedException, IOException, InvalidModificationException, EncodingException, FileExistsException {
-        fileName = stripFileProtocol(fileName);
-        newParent = stripFileProtocol(newParent);
+        String newFileName = getRealPathFromURI(Uri.parse(fileName), cordova);
+        newParent = getRealPathFromURI(Uri.parse(newParent), cordova);
 
         // Check for invalid file name
         if (newName != null && newName.contains(":")) {
             throw new EncodingException("Bad file name");
         }
 
-        File source = new File(fileName);
+        File source = new File(newFileName);
 
         if (!source.exists()) {
             // The file/directory we are copying doesn't exist so we should fail.
@@ -385,7 +384,14 @@
             }
         } else {
             if (move) {
-                return 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);
+            	}
+
+            	return newFileEntry;
             } else {
                 return copyFile(source, destination);
             }
@@ -483,7 +489,7 @@
         if (!destinationDir.exists()) {
             if (!destinationDir.mkdir()) {
                 // If we can't create the directory then fail
-                throw new NoModificationAllowedException("Couldn't create the destination direcotry");
+                throw new NoModificationAllowedException("Couldn't create the destination directory");
             }
         }
 
@@ -561,8 +567,8 @@
      * @throws JSONException
      * @throws IOException
      * @throws InvalidModificationException
-     * @throws NoModificationAllowedException 
-     * @throws FileExistsException 
+     * @throws NoModificationAllowedException
+     * @throws FileExistsException
      */
     private JSONObject moveDirectory(File srcDir, File destinationDir) throws IOException, JSONException, InvalidModificationException, NoModificationAllowedException, FileExistsException {
         // Renaming a file to an existing directory should fail
@@ -742,7 +748,7 @@
         if (fileName.startsWith("/")) {
             fp = new File(fileName);
         } else {
-            dirPath = stripFileProtocol(dirPath);
+            dirPath = getRealPathFromURI(Uri.parse(dirPath), cordova);
             fp = new File(dirPath + File.separator + fileName);
         }
         return fp;
@@ -757,7 +763,7 @@
      * @throws JSONException
      */
     private JSONObject getParent(String filePath) throws JSONException {
-        filePath = stripFileProtocol(filePath);
+        filePath = getRealPathFromURI(Uri.parse(filePath), cordova);
 
         if (atRootDirectory(filePath)) {
             return getEntry(filePath);
@@ -773,7 +779,7 @@
      * @return true if we are at the root, false otherwise.
      */
     private boolean atRootDirectory(String filePath) {
-        filePath = stripFileProtocol(filePath);
+        filePath = getRealPathFromURI(Uri.parse(filePath), cordova);
 
         if (filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + cordova.getActivity().getPackageName() + "/cache") ||
                 filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath()) ||
@@ -803,7 +809,7 @@
      * @return
      */
     private File createFileObject(String filePath) {
-        filePath = stripFileProtocol(filePath);
+    	filePath = getRealPathFromURI(Uri.parse(filePath), cordova);
 
         File file = new File(filePath);
         return file;
@@ -845,7 +851,7 @@
         metadata.put("size", file.length());
         metadata.put("type", getMimeType(filePath));
         metadata.put("name", file.getName());
-        metadata.put("fullPath", file.getAbsolutePath());
+        metadata.put("fullPath", filePath);
         metadata.put("lastModifiedDate", file.lastModified());
 
         return metadata;
@@ -1028,7 +1034,7 @@
         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();
@@ -1050,10 +1056,15 @@
      * @param data				The contents of the file.
      * @param offset			The position to begin writing the file.
      * @throws FileNotFoundException, IOException
+     * @throws NoModificationAllowedException
      */
     /**/
-    public long write(String filename, String data, int offset) throws FileNotFoundException, IOException {
-        filename = stripFileProtocol(filename);
+    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");
+    	}
+
+        filename = getRealPathFromURI(Uri.parse(filename), cordova);
 
         boolean append = false;
         if (offset > 0) {
@@ -1079,9 +1090,14 @@
      * @param filename
      * @param size
      * @throws FileNotFoundException, IOException
+     * @throws NoModificationAllowedException
      */
-    private long truncateFile(String filename, long size) throws FileNotFoundException, IOException {
-        filename = stripFileProtocol(filename);
+    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");
+    	}
+
+        filename = getRealPathFromURI(Uri.parse(filename), cordova);
 
         RandomAccessFile raf = new RandomAccessFile(filename, "rw");
         try {
@@ -1090,7 +1106,7 @@
                 channel.truncate(size);
                 return size;
             }
-    
+
             return raf.length();
         } finally {
             raf.close();
@@ -1110,7 +1126,7 @@
             return cordova.getActivity().getContentResolver().openInputStream(uri);
         }
         else {
-            path = stripFileProtocol(path);
+            path = getRealPathFromURI(Uri.parse(path), cordova);
             return new FileInputStream(path);
         }
     }
@@ -1125,8 +1141,10 @@
     @SuppressWarnings("deprecation")
     protected static String getRealPathFromURI(Uri contentUri, CordovaInterface cordova) {
         final String scheme = contentUri.getScheme();
-        
-        if (scheme.compareTo("content") == 0) {
+
+        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);
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 0d83432..7e7f862 100644
--- a/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/InAppBrowser.java
@@ -23,6 +23,7 @@
 
 import org.apache.cordova.api.CallbackContext;
 import org.apache.cordova.api.CordovaPlugin;
+import org.apache.cordova.api.LOG;
 import org.apache.cordova.api.PluginResult;
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -48,6 +49,7 @@
 import android.view.inputmethod.InputMethodManager;
 import android.webkit.WebChromeClient;
 import android.webkit.WebSettings;
+import android.webkit.WebStorage;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
 import android.widget.Button;
@@ -67,13 +69,14 @@
     private static final String EXIT_EVENT = "exit";
     private static final String LOAD_START_EVENT = "loadstart";
     private static final String LOAD_STOP_EVENT = "loadstop";
+    private long MAX_QUOTA = 100 * 1024 * 1024;
 
     private Dialog dialog;
     private WebView inAppWebView;
     private EditText edittext;
     private boolean showLocationBar = true;
     private CallbackContext callbackContext;
-
+    
     /**
      * Executes the request and returns PluginResult.
      *
@@ -108,6 +111,17 @@
                             || Config.isUrlWhiteListed(url)) {
                         this.webView.loadUrl(url);
                     }
+                    //Load the dialer
+                    else if (url.startsWith(WebView.SCHEME_TEL))
+                    {
+                        try {
+                            Intent intent = new Intent(Intent.ACTION_DIAL);
+                            intent.setData(Uri.parse(url));
+                            this.cordova.getActivity().startActivity(intent);
+                        } catch (android.content.ActivityNotFoundException e) {
+                            LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
+                        }
+                    }
                     // load in InAppBrowser
                     else {
                         result = this.showWebPage(url, features);
@@ -401,7 +415,7 @@
                 // WebView
                 inAppWebView = new WebView(cordova.getActivity());
                 inAppWebView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
-                inAppWebView.setWebChromeClient(new WebChromeClient());
+                inAppWebView.setWebChromeClient(new InAppChromeClient());
                 WebViewClient client = new InAppBrowserClient(thatWebView, edittext);
                 inAppWebView.setWebViewClient(client);
                 WebSettings settings = inAppWebView.getSettings();
@@ -468,6 +482,40 @@
         this.callbackContext.sendPluginResult(result);
     }
 
+    public class InAppChromeClient extends WebChromeClient {
+
+        /**
+         * Handle database quota exceeded notification.
+         *
+         * @param url
+         * @param databaseIdentifier
+         * @param currentQuota
+         * @param estimatedSize
+         * @param totalUsedQuota
+         * @param quotaUpdater
+         */
+        @Override
+        public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize,
+                long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater)
+        {
+            LOG.d(LOG_TAG, "onExceededDatabaseQuota estimatedSize: %d  currentQuota: %d  totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota);
+
+            if (estimatedSize < MAX_QUOTA)
+            {
+                //increase for 1Mb
+                long newQuota = estimatedSize;
+                LOG.d(LOG_TAG, "calling quotaUpdater.updateQuota newQuota: %d", newQuota);
+                quotaUpdater.updateQuota(newQuota);
+            }
+            else
+            {
+                // Set the quota to whatever it is and force an error
+                // TODO: get docs on how to handle this properly
+                quotaUpdater.updateQuota(currentQuota);
+            }
+        }
+    }
+    
     /**
      * The webview client receives notifications about appView
      */
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/Storage.java b/lib/cordova-android/framework/src/org/apache/cordova/Storage.java
index 5ec3068..34ebf38 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/Storage.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/Storage.java
@@ -22,7 +22,6 @@
 
 import org.apache.cordova.api.CallbackContext;
 import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
diff --git a/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaInterface.java b/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaInterface.java
index 22e36b6..aaa5885 100755
--- a/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaInterface.java
+++ b/lib/cordova-android/framework/src/org/apache/cordova/api/CordovaInterface.java
@@ -19,7 +19,6 @@
 package org.apache.cordova.api;
 
 import android.app.Activity;
-import android.content.Context;
 import android.content.Intent;
 
 import java.util.concurrent.ExecutorService;
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 98bb157..d0e6aef 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
@@ -22,17 +22,13 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map.Entry;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 
 import org.apache.cordova.CordovaWebView;
-import org.json.JSONArray;
 import org.json.JSONException;
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.content.Intent;
 import android.content.res.XmlResourceParser;
-import android.util.Log;
 
 /**
  * PluginManager is exposed to JavaScript in the Cordova WebView.
diff --git a/lib/cordova-android/test/res/xml/config.xml b/lib/cordova-android/test/res/xml/config.xml
index b9ae3a6..675aeb5 100644
--- a/lib/cordova-android/test/res/xml/config.xml
+++ b/lib/cordova-android/test/res/xml/config.xml
@@ -45,12 +45,13 @@
     <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"/>
     <plugin name="Echo" value="org.apache.cordova.Echo" />
+    <plugin name="Globalization" value="org.apache.cordova.Globalization"/>
+    <plugin name="InAppBrowser" value="org.apache.cordova.InAppBrowser"/>
 </plugins>
 </cordova>
 
diff --git a/lib/cordova-android/test/src/org/apache/cordova/test/ActivityPlugin.java b/lib/cordova-android/test/src/org/apache/cordova/test/ActivityPlugin.java
index 805454a..0c1d1da 100755
--- a/lib/cordova-android/test/src/org/apache/cordova/test/ActivityPlugin.java
+++ b/lib/cordova-android/test/src/org/apache/cordova/test/ActivityPlugin.java
@@ -18,19 +18,21 @@
 */
 package org.apache.cordova.test;
 
+import org.apache.cordova.CordovaArgs;
 import org.apache.cordova.api.LOG;
 import org.json.JSONArray;
 import org.json.JSONException;
 
 import android.content.Intent;
 
-import org.apache.cordova.api.Plugin;
+import org.apache.cordova.api.CallbackContext;
+import org.apache.cordova.api.CordovaPlugin;
 import org.apache.cordova.api.PluginResult;
 
 /**
  * This class provides a service.
  */
-public class ActivityPlugin extends Plugin {
+public class ActivityPlugin extends CordovaPlugin {
 
     static String TAG = "ActivityPlugin";
 
@@ -48,19 +50,21 @@
      * @param callbackId    The callback id used when calling back into JavaScript.
      * @return              A PluginResult object with a status and message.
      */
-    @Override
-    public PluginResult execute(String action, JSONArray args, String callbackId) {
-        PluginResult.Status status = PluginResult.Status.OK;
-        String result = "";
-
+    public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) {
+        PluginResult result = new PluginResult(PluginResult.Status.OK, "");
         try {
             if (action.equals("start")) {
                 this.startActivity(args.getString(0));
+                callbackContext.sendPluginResult(result);
+                callbackContext.success();
+                return true;
             }
-            return new PluginResult(status, result);
         } catch (JSONException e) {
-            return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
+            result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, "JSON Exception");
+            callbackContext.sendPluginResult(result);
+            return false;
         }
+        return false;
     }
 
     // --------------------------------------------------------------------------
@@ -69,9 +73,9 @@
 
     public void startActivity(String className) {
         try {
-            Intent intent = new Intent().setClass(this.ctx.getActivity(), Class.forName(className));
+            Intent intent = new Intent().setClass(this.cordova.getActivity(), Class.forName(className));
             LOG.d(TAG, "Starting activity %s", className);
-            this.ctx.getActivity().startActivity(intent);
+            this.cordova.getActivity().startActivity(intent);
         } catch (ClassNotFoundException e) {
             e.printStackTrace();
             LOG.e(TAG, "Error starting activity %s", className);
diff --git a/lib/cordova-blackberry/README.md b/lib/cordova-blackberry/README.md
index b504c42..e2f9896 100644
--- a/lib/cordova-blackberry/README.md
+++ b/lib/cordova-blackberry/README.md
@@ -7,7 +7,7 @@
 -------------------
 
     framework/ ... BlackBerry WebWorks JavaScript Extension (Cordova native code)
-    javascript/ .. Cordova JavaScript (Non-concatenated, non-minified)
+    javascript/ .. Cordova JavaScript (concatenated, non-minified)
     bin/ ......... Scripts for project creation
 
 Introduction
@@ -47,7 +47,7 @@
 
 ### General Commands
 
-    ./bin/create [path appname] ............ creates a sample app with the specified application name, to the specified path
+    ./bin/create [path appname packagename] ............ creates a sample app with the specified application name, to the specified path
 
 Please note that once you `create` a Cordova BlackBerry project, you
 will need to edit the `project.properties` file that resides inside your
@@ -67,11 +67,11 @@
 
     ./bin/create
     cd example
-    ./cordova/debug
+    ./cordova/run blackberry
 
 #### Creating a new Cordova BlackBerry Project
 
-    ./bin/create ~/Desktop/myapp MyApp
+    ./bin/create ~/Desktop/myapp MyAppName MyAppPackageName
 
 ### Project Commands
 
diff --git a/lib/cordova-blackberry/VERSION b/lib/cordova-blackberry/VERSION
index 197c4d5..aa0822f 100644
--- a/lib/cordova-blackberry/VERSION
+++ b/lib/cordova-blackberry/VERSION
@@ -1 +1 @@
-2.4.0
+2.5.0rc1
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
new file mode 100644
index 0000000..0625376
--- /dev/null
+++ b/lib/cordova-blackberry/bin/templates/project/lib/ant-contrib/ant-contrib-1.0b3.jar
Binary files differ
diff --git a/lib/cordova-blackberry/bin/templates/project/www/VERSION b/lib/cordova-blackberry/bin/templates/project/www/VERSION
index 2eca156..aa0822f 100644
--- a/lib/cordova-blackberry/bin/templates/project/www/VERSION
+++ b/lib/cordova-blackberry/bin/templates/project/www/VERSION
@@ -1 +1 @@
-2.4.0rc1
+2.5.0rc1
diff --git a/lib/cordova-blackberry/bin/templates/project/www/index.html b/lib/cordova-blackberry/bin/templates/project/www/index.html
index f3c00e2..ab0ca50 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.4.0.js"></script>
+        <script type="text/javascript" src="cordova-2.5.0rc1.js"></script>
         <script type="text/javascript" src="js/index.js"></script>
         <script type="text/javascript">
             app.initialize();
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 e11f924..1e56cee 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 @@
 				JSONObject device = new JSONObject();
 				device.put( FIELD_PLATFORM, "BlackBerry");
 				device.put( FIELD_UUID, new Integer( DeviceInfo.getDeviceId()) );
-				device.put( FIELD_CORDOVA, "2.4.0rc1" );
+				device.put( FIELD_CORDOVA, "2.5.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()) );
diff --git a/lib/cordova-blackberry/javascript/cordova.blackberry.js b/lib/cordova-blackberry/javascript/cordova.blackberry.js
index a963a2d..cb48379 100644
--- a/lib/cordova-blackberry/javascript/cordova.blackberry.js
+++ b/lib/cordova-blackberry/javascript/cordova.blackberry.js
@@ -1,8 +1,8 @@
 // Platform: blackberry
 
-// commit ac725f6ae0bd655789771e2a40b8d60cb4c8c221
+// commit cded0ad0826489ca07ae8bdd33905a37d40f3adf
 
-// File generated at :: Tue Feb 05 2013 16:15:50 GMT-0800 (PST)
+// File generated at :: Wed Feb 20 2013 13:20:15 GMT-0800 (PST)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -399,6 +399,7 @@
 }
 
 function clobber(obj, key, value) {
+    exports.replaceHookForTesting(obj, key);
     obj[key] = value;
     // Getters can only be overridden by getters.
     if (obj[key] !== value) {
@@ -482,19 +483,18 @@
     }
 }
 
-module.exports = {
-    buildIntoButDoNotClobber: function(objects, target) {
-        include(target, objects, false, false);
-    },
-    buildIntoAndClobber: function(objects, target) {
-        include(target, objects, true, false);
-    },
-    buildIntoAndMerge: function(objects, target) {
-        include(target, objects, true, true);
-    },
-    recursiveMerge: recursiveMerge,
-    assignOrWrapInDeprecateGetter: assignOrWrapInDeprecateGetter
+exports.buildIntoButDoNotClobber = function(objects, target) {
+    include(target, objects, false, false);
 };
+exports.buildIntoAndClobber = function(objects, target) {
+    include(target, objects, true, false);
+};
+exports.buildIntoAndMerge = function(objects, target) {
+    include(target, objects, true, true);
+};
+exports.recursiveMerge = recursiveMerge;
+exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
+exports.replaceHookForTesting = function() {};
 
 });
 
@@ -774,176 +774,6 @@
 };
 });
 
-// file: lib/common/common.js
-define("cordova/common", function(require, exports, module) {
-
-module.exports = {
-    defaults: {
-        cordova: {
-            path: 'cordova',
-            children: {
-                exec: {
-                    path: 'cordova/exec'
-                },
-                logger: {
-                    path: 'cordova/plugin/logger'
-                }
-            }
-        },
-        Cordova: {
-            children: {
-                exec: {
-                    path: 'cordova/exec'
-                }
-            }
-        },
-        open : {
-            path: 'cordova/plugin/InAppBrowser'
-        },
-        navigator: {
-            children: {
-                notification: {
-                    path: 'cordova/plugin/notification'
-                },
-                accelerometer: {
-                    path: 'cordova/plugin/accelerometer'
-                },
-                battery: {
-                    path: 'cordova/plugin/battery'
-                },
-                camera:{
-                    path: 'cordova/plugin/Camera'
-                },
-                compass:{
-                    path: 'cordova/plugin/compass'
-                },
-                contacts: {
-                    path: 'cordova/plugin/contacts'
-                },
-                device:{
-                    children:{
-                        capture: {
-                            path: 'cordova/plugin/capture'
-                        }
-                    }
-                },
-                geolocation: {
-                    path: 'cordova/plugin/geolocation'
-                },
-                globalization: {
-                    path: 'cordova/plugin/globalization'
-                },
-                network: {
-                    children: {
-                        connection: {
-                            path: 'cordova/plugin/network',
-                            deprecated: 'navigator.network.connection is deprecated. Use navigator.connection instead.'
-                        }
-                    }
-                },
-                splashscreen: {
-                    path: 'cordova/plugin/splashscreen'
-                }
-            }
-        },
-        Acceleration: {
-            path: 'cordova/plugin/Acceleration'
-        },
-        Camera:{
-            path: 'cordova/plugin/CameraConstants'
-        },
-        CameraPopoverOptions: {
-            path: 'cordova/plugin/CameraPopoverOptions'
-        },
-        CaptureError: {
-            path: 'cordova/plugin/CaptureError'
-        },
-        CaptureAudioOptions:{
-            path: 'cordova/plugin/CaptureAudioOptions'
-        },
-        CaptureImageOptions: {
-            path: 'cordova/plugin/CaptureImageOptions'
-        },
-        CaptureVideoOptions: {
-            path: 'cordova/plugin/CaptureVideoOptions'
-        },
-        CompassHeading:{
-            path: 'cordova/plugin/CompassHeading'
-        },
-        CompassError:{
-            path: 'cordova/plugin/CompassError'
-        },
-        ConfigurationData: {
-            path: 'cordova/plugin/ConfigurationData'
-        },
-        Connection: {
-            path: 'cordova/plugin/Connection'
-        },
-        Contact: {
-            path: 'cordova/plugin/Contact'
-        },
-        ContactAddress: {
-            path: 'cordova/plugin/ContactAddress'
-        },
-        ContactError: {
-            path: 'cordova/plugin/ContactError'
-        },
-        ContactField: {
-            path: 'cordova/plugin/ContactField'
-        },
-        ContactFindOptions: {
-            path: 'cordova/plugin/ContactFindOptions'
-        },
-        ContactName: {
-            path: 'cordova/plugin/ContactName'
-        },
-        ContactOrganization: {
-            path: 'cordova/plugin/ContactOrganization'
-        },
-        Coordinates: {
-            path: 'cordova/plugin/Coordinates'
-        },
-        device: {
-            path: 'cordova/plugin/device'
-        },
-        GlobalizationError: {
-            path: 'cordova/plugin/GlobalizationError'
-        },
-        Media: {
-            path: 'cordova/plugin/Media'
-        },
-        MediaError: {
-            path: 'cordova/plugin/MediaError'
-        },
-        MediaFile: {
-            path: 'cordova/plugin/MediaFile'
-        },
-        MediaFileData:{
-            path: 'cordova/plugin/MediaFileData'
-        },
-        Position: {
-            path: 'cordova/plugin/Position'
-        },
-        PositionError: {
-            path: 'cordova/plugin/PositionError'
-        },
-        ProgressEvent: {
-            path: 'cordova/plugin/ProgressEvent'
-        }
-    },
-    clobbers: {
-        navigator: {
-            children: {
-                connection: {
-                    path: 'cordova/plugin/network'
-                }
-            }
-        }
-    }
-};
-
-});
-
 // file: lib/blackberry/exec.js
 define("cordova/exec", function(require, exports, module) {
 
@@ -1051,9 +881,9 @@
     var parts = symbolPath.split('.');
     var cur = context;
     for (var i = 0, part; part = parts[i]; ++i) {
-        cur[part] = cur[part] || {};
+        cur = cur[part] = cur[part] || {};
     }
-    return cur[parts[i-1]];
+    return cur;
 }
 
 exports.mapModules = function(context) {
@@ -1075,7 +905,7 @@
         if (strategy == 'm' && target) {
             builder.recursiveMerge(target, module);
         } else if ((strategy == 'd' && !target) || (strategy != 'd')) {
-            if (target) {
+            if (!(symbolPath in origSymbols)) {
                 origSymbols[symbolPath] = target;
             }
             builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
@@ -1130,20 +960,16 @@
         }
     },
     initialize: function() {
-        var builder = require('cordova/builder'),
-            modulemapper = require('cordova/modulemapper'),
+        var modulemapper = require('cordova/modulemapper'),
             platform = require('cordova/plugin/' + this.runtime() + '/platform');
 
-        builder.buildIntoButDoNotClobber(platform.defaults, window);
-        builder.buildIntoAndClobber(platform.clobbers, window);
-        builder.buildIntoAndMerge(platform.merges, window);
-
         modulemapper.loadMatchingModules(/cordova.*\/symbols$/);
         modulemapper.loadMatchingModules(new RegExp('cordova/.*' + this.runtime() + '/.*bbsymbols$'));
-        modulemapper.mapModules(window);
+        modulemapper.mapModules(this.contextObj);
 
         platform.initialize();
-    }
+    },
+    contextObj: this // Used for testing.
 };
 
 });
@@ -1376,9 +1202,9 @@
 define("cordova/plugin/CompassHeading", function(require, exports, module) {
 
 var CompassHeading = function(magneticHeading, trueHeading, headingAccuracy, timestamp) {
-  this.magneticHeading = magneticHeading || null;
-  this.trueHeading = trueHeading || null;
-  this.headingAccuracy = headingAccuracy || null;
+  this.magneticHeading = magneticHeading;
+  this.trueHeading = trueHeading;
+  this.headingAccuracy = headingAccuracy;
   this.timestamp = timestamp || new Date().getTime();
 };
 
@@ -2751,11 +2577,12 @@
  * FileTransferError
  * @constructor
  */
-var FileTransferError = function(code, source, target, status) {
+var FileTransferError = function(code, source, target, status, body) {
     this.code = code || null;
     this.source = source || null;
     this.target = target || null;
     this.http_status = status || null;
+    this.body = body || null;
 };
 
 FileTransferError.FILE_NOT_FOUND_ERR = 1;
@@ -3159,8 +2986,6 @@
     return iab;
 };
 
-//Export the original open so it can be used if needed
-module.exports._orig = window.open;
 
 });
 
@@ -3731,6 +3556,17 @@
 
 });
 
+// file: lib/common/plugin/accelerometer/symbols.js
+define("cordova/plugin/accelerometer/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Acceleration', 'Acceleration');
+modulemapper.defaults('cordova/plugin/accelerometer', 'navigator.accelerometer');
+
+});
+
 // file: lib/blackberry/plugin/air/DirectoryEntry.js
 define("cordova/plugin/air/DirectoryEntry", function(require, exports, module) {
 
@@ -5348,7 +5184,7 @@
                     model: "PlayBook",
                     name: "PlayBook", // deprecated: please use device.model
                     uuid: info.uuid,
-                    cordova: "2.4.0"
+                    cordova: "2.5.0rc1"
                 });
             }),
             request = new blackberry.transport.RemoteFunctionCall("org/apache/cordova/getDeviceInfo");
@@ -5708,6 +5544,28 @@
 
 });
 
+// file: lib/common/plugin/battery/symbols.js
+define("cordova/plugin/battery/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/battery', 'navigator.battery');
+
+});
+
+// file: lib/common/plugin/camera/symbols.js
+define("cordova/plugin/camera/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Camera', 'navigator.camera');
+modulemapper.defaults('cordova/plugin/CameraConstants', 'Camera');
+modulemapper.defaults('cordova/plugin/CameraPopoverOptions', 'CameraPopoverOptions');
+
+});
+
 // file: lib/common/plugin/capture.js
 define("cordova/plugin/capture", function(require, exports, module) {
 
@@ -5786,6 +5644,22 @@
 
 });
 
+// file: lib/common/plugin/capture/symbols.js
+define("cordova/plugin/capture/symbols", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/CaptureError', 'CaptureError');
+modulemapper.clobbers('cordova/plugin/CaptureAudioOptions', 'CaptureAudioOptions');
+modulemapper.clobbers('cordova/plugin/CaptureImageOptions', 'CaptureImageOptions');
+modulemapper.clobbers('cordova/plugin/CaptureVideoOptions', 'CaptureVideoOptions');
+modulemapper.clobbers('cordova/plugin/ConfigurationData', 'ConfigurationData');
+modulemapper.clobbers('cordova/plugin/MediaFile', 'MediaFile');
+modulemapper.clobbers('cordova/plugin/MediaFileData', 'MediaFileData');
+modulemapper.clobbers('cordova/plugin/capture', 'navigator.device.capture');
+
+});
+
 // file: lib/common/plugin/compass.js
 define("cordova/plugin/compass", function(require, exports, module) {
 
@@ -5873,6 +5747,18 @@
 
 });
 
+// file: lib/common/plugin/compass/symbols.js
+define("cordova/plugin/compass/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/CompassHeading', 'CompassHeading');
+modulemapper.clobbers('cordova/plugin/CompassError', 'CompassError');
+modulemapper.clobbers('cordova/plugin/compass', 'navigator.compass');
+
+});
+
 // file: lib/common/plugin/console-via-logger.js
 define("cordova/plugin/console-via-logger", function(require, exports, module) {
 
@@ -6106,6 +5992,23 @@
 
 });
 
+// file: lib/common/plugin/contacts/symbols.js
+define("cordova/plugin/contacts/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/contacts', 'navigator.contacts');
+modulemapper.clobbers('cordova/plugin/Contact', 'Contact');
+modulemapper.clobbers('cordova/plugin/ContactAddress', 'ContactAddress');
+modulemapper.clobbers('cordova/plugin/ContactError', 'ContactError');
+modulemapper.clobbers('cordova/plugin/ContactField', 'ContactField');
+modulemapper.clobbers('cordova/plugin/ContactFindOptions', 'ContactFindOptions');
+modulemapper.clobbers('cordova/plugin/ContactName', 'ContactName');
+modulemapper.clobbers('cordova/plugin/ContactOrganization', 'ContactOrganization');
+
+});
+
 // file: lib/common/plugin/device.js
 define("cordova/plugin/device", function(require, exports, module) {
 
@@ -6165,6 +6068,16 @@
 
 });
 
+// file: lib/common/plugin/device/symbols.js
+define("cordova/plugin/device/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/device', 'device');
+
+});
+
 // file: lib/common/plugin/echo.js
 define("cordova/plugin/echo", function(require, exports, module) {
 
@@ -6211,20 +6124,30 @@
     exportFunc('cordova/plugin/FileError', 'FileError');
     exportFunc('cordova/plugin/FileReader', 'FileReader');
     exportFunc('cordova/plugin/FileSystem', 'FileSystem');
-    exportFunc('cordova/plugin/FileTransfer', 'FileTransfer');
-    exportFunc('cordova/plugin/FileTransferError', 'FileTransferError');
     exportFunc('cordova/plugin/FileUploadOptions', 'FileUploadOptions');
     exportFunc('cordova/plugin/FileUploadResult', 'FileUploadResult');
     exportFunc('cordova/plugin/FileWriter', 'FileWriter');
     exportFunc('cordova/plugin/Flags', 'Flags');
     exportFunc('cordova/plugin/LocalFileSystem', 'LocalFileSystem');
     exportFunc('cordova/plugin/Metadata', 'Metadata');
+    exportFunc('cordova/plugin/ProgressEvent', 'ProgressEvent');
     exportFunc('cordova/plugin/requestFileSystem', 'requestFileSystem');
     exportFunc('cordova/plugin/resolveLocalFileSystemURI', 'resolveLocalFileSystemURI');
 };
 
 });
 
+// file: lib/common/plugin/filetransfer/symbols.js
+define("cordova/plugin/filetransfer/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/FileTransfer', 'FileTransfer');
+modulemapper.clobbers('cordova/plugin/FileTransferError', 'FileTransferError');
+
+});
+
 // file: lib/common/plugin/geolocation.js
 define("cordova/plugin/geolocation", function(require, exports, module) {
 
@@ -6421,6 +6344,19 @@
 
 });
 
+// file: lib/common/plugin/geolocation/symbols.js
+define("cordova/plugin/geolocation/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/geolocation', 'navigator.geolocation');
+modulemapper.clobbers('cordova/plugin/PositionError', 'PositionError');
+modulemapper.clobbers('cordova/plugin/Position', 'Position');
+modulemapper.clobbers('cordova/plugin/Coordinates', 'Coordinates');
+
+});
+
 // file: lib/common/plugin/globalization.js
 define("cordova/plugin/globalization", function(require, exports, module) {
 
@@ -6797,6 +6733,17 @@
 
 });
 
+// file: lib/common/plugin/globalization/symbols.js
+define("cordova/plugin/globalization/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/globalization', 'navigator.globalization');
+modulemapper.clobbers('cordova/plugin/GlobalizationError', 'GlobalizationError');
+
+});
+
 // file: lib/blackberry/plugin/java/Contact.js
 define("cordova/plugin/java/Contact", function(require, exports, module) {
 
@@ -7965,6 +7912,16 @@
 
 });
 
+// file: lib/blackberry/plugin/java/app/bbsymbols.js
+define("cordova/plugin/java/app/bbsymbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/java/app', 'navigator.app');
+
+});
+
 // file: lib/blackberry/plugin/java/contacts.js
 define("cordova/plugin/java/contacts", function(require, exports, module) {
 
@@ -8034,6 +7991,17 @@
 
 });
 
+// file: lib/blackberry/plugin/java/contacts/bbsymbols.js
+define("cordova/plugin/java/contacts/bbsymbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.merges('cordova/plugin/java/contacts', 'navigator.contacts');
+modulemapper.merges('cordova/plugin/java/Contact', 'Contact');
+
+});
+
 // file: lib/blackberry/plugin/java/file/bbsymbols.js
 define("cordova/plugin/java/file/bbsymbols", function(require, exports, module) {
 
@@ -8123,6 +8091,19 @@
 
 });
 
+// file: lib/blackberry/plugin/java/media/bbsymbols.js
+define("cordova/plugin/java/media/bbsymbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Media', 'Media');
+modulemapper.defaults('cordova/plugin/MediaError', 'MediaError');
+// Exists natively on BB OS 6+, merge in Cordova specifics
+modulemapper.merges('cordova/plugin/java/MediaError', 'MediaError');
+
+});
+
 // file: lib/blackberry/plugin/java/notification.js
 define("cordova/plugin/java/notification", function(require, exports, module) {
 
@@ -8182,6 +8163,16 @@
 
 });
 
+// file: lib/blackberry/plugin/java/notification/bbsymbols.js
+define("cordova/plugin/java/notification/bbsymbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.merges('cordova/plugin/java/notification', 'navigator.notification');
+
+});
+
 // file: lib/blackberry/plugin/java/platform.js
 define("cordova/plugin/java/platform", function(require, exports, module) {
 
@@ -8310,33 +8301,6 @@
 
         // Trap BlackBerry WebWorks exit. Allow plugins to clean up before exiting.
         blackberry.app.event.onExit(app.exitApp);
-    },
-    clobbers: {
-        navigator: {
-            children: {
-                app: {
-                    path: "cordova/plugin/java/app"
-                }
-            }
-        }
-    },
-    merges: {
-        navigator: {
-            children: {
-                contacts: {
-                    path: 'cordova/plugin/java/contacts'
-                },
-                notification: {
-                    path: 'cordova/plugin/java/notification'
-                }
-            }
-        },
-        Contact: {
-            path: 'cordova/plugin/java/Contact'
-        },
-        MediaError: { // Exists natively on BB OS 6+, merge in Cordova specifics
-            path: 'cordova/plugin/java/MediaError'
-        }
     }
 };
 
@@ -8570,6 +8534,27 @@
 
 });
 
+// file: lib/common/plugin/logger/symbols.js
+define("cordova/plugin/logger/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/logger', 'cordova.logger');
+
+});
+
+// file: lib/common/plugin/media/symbols.js
+define("cordova/plugin/media/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Media', 'Media');
+modulemapper.defaults('cordova/plugin/MediaError', 'MediaError');
+
+});
+
 // file: lib/common/plugin/network.js
 define("cordova/plugin/network", function(require, exports, module) {
 
@@ -8642,6 +8627,18 @@
 
 });
 
+// file: lib/common/plugin/networkstatus/symbols.js
+define("cordova/plugin/networkstatus/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/network', 'navigator.network.connection', 'navigator.network.connection is deprecated. Use navigator.connection instead.');
+modulemapper.clobbers('cordova/plugin/network', 'navigator.connection');
+modulemapper.defaults('cordova/plugin/Connection', 'Connection');
+
+});
+
 // file: lib/common/plugin/notification.js
 define("cordova/plugin/notification", function(require, exports, module) {
 
@@ -8704,18 +8701,29 @@
 
 });
 
+// file: lib/common/plugin/notification/symbols.js
+define("cordova/plugin/notification/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/notification', 'navigator.notification');
+
+});
+
 // file: lib/blackberry/plugin/qnx/InAppBrowser.js
 define("cordova/plugin/qnx/InAppBrowser", function(require, exports, module) {
 
 var cordova = require('cordova'),
-    core = require('cordova/plugin/InAppBrowser'),
+    modulemapper = require('cordova/modulemapper'),
+    origOpen = modulemapper.getOriginalSymbol(window, 'open'),
     browser = {
         close: function () { } //dummy so we don't have to check for undefined
     };
 
 var navigate = {
     "_blank": function (url, whitelisted) {
-        return core._orig.apply(null, [url, "_blank"]);
+        return origOpen(url, "_blank");
     },
 
     "_self": function (url, whitelisted) {
@@ -8724,7 +8732,7 @@
             return window;
         }
         else {
-            return core._orig.apply(null, [url, "_blank"]);
+            return origOpen(url, "_blank");
         }
     },
 
@@ -9024,6 +9032,16 @@
 
 });
 
+// file: lib/blackberry/plugin/qnx/compass/bbsymbols.js
+define("cordova/plugin/qnx/compass/bbsymbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.merges('cordova/plugin/qnx/compass', 'navigator.compass');
+
+});
+
 // file: lib/blackberry/plugin/qnx/device.js
 define("cordova/plugin/qnx/device", function(require, exports, module) {
 
@@ -9041,7 +9059,7 @@
             model: "Dev Alpha",
             name: "Dev Alpha", // deprecated: please use device.model
             uuid: blackberry.identity.uuid,
-            cordova: "2.4.0"
+            cordova: "2.5.0rc1"
         });
 
         return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "Device info returned" };
@@ -9490,6 +9508,16 @@
 
 });
 
+// file: lib/blackberry/plugin/qnx/inappbrowser/bbsymbols.js
+define("cordova/plugin/qnx/inappbrowser/bbsymbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/InAppBrowser', 'open');
+
+});
+
 // file: lib/blackberry/plugin/qnx/magnetometer.js
 define("cordova/plugin/qnx/magnetometer", function(require, exports, module) {
 
@@ -9602,20 +9630,6 @@
                 cordova.fireDocumentEvent("offline");
             });
         });
-    },
-    clobbers: {
-        open: {
-            path: "cordova/plugin/InAppBrowser"
-        }
-    },
-    merges: {
-        navigator: {
-            children: {
-                compass: {
-                    path: 'cordova/plugin/qnx/compass'
-                }
-            }
-        }
     }
 };
 
@@ -9734,6 +9748,16 @@
 
 });
 
+// file: lib/common/plugin/splashscreen/symbols.js
+define("cordova/plugin/splashscreen/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/splashscreen', 'navigator.splashscreen');
+
+});
+
 // file: lib/blackberry/plugin/webworks/accelerometer.js
 define("cordova/plugin/webworks/accelerometer", function(require, exports, module) {
 
@@ -9791,7 +9815,7 @@
 
         var id = args[0],
             src = args[1];
-        
+
         if (typeof src == "undefined"){
             audioObjects[id] = new Audio();
         } else {
@@ -9988,6 +10012,19 @@
 
 });
 
+// file: lib/common/symbols.js
+define("cordova/symbols", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+// Use merges here in case others symbols files depend on this running first,
+// but fail to declare the dependency with a require().
+modulemapper.merges('cordova', 'cordova');
+modulemapper.clobbers('cordova/exec', 'cordova.exec');
+modulemapper.clobbers('cordova/exec', 'Cordova.exec');
+
+});
+
 // file: lib/common/utils.js
 define("cordova/utils", function(require, exports, module) {
 
@@ -10255,18 +10292,7 @@
                  * Create all cordova objects once page has fully loaded and native side is ready.
                  */
                 channel.join(function() {
-                    var builder = require('cordova/builder'),
-                        base = require('cordova/common'),
-                        platform = require('cordova/platform');
-
-                    // Drop the common globals into the window object, but be nice and don't overwrite anything.
-                    builder.buildIntoButDoNotClobber(base.defaults, context);
-                    builder.buildIntoAndClobber(base.clobbers, context);
-                    builder.buildIntoAndMerge(base.merges, context);
-
-                    builder.buildIntoButDoNotClobber(platform.defaults, context);
-                    builder.buildIntoAndClobber(platform.clobbers, context);
-                    builder.buildIntoAndMerge(platform.merges, context);
+                    var platform = require('cordova/platform');
 
                     // Call the platform-specific initialization
                     platform.initialize();
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h b/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
index 67583be..33c6799 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVAvailability.h
@@ -36,6 +36,7 @@
 #define __CORDOVA_2_2_0 20200
 #define __CORDOVA_2_3_0 20300
 #define __CORDOVA_2_4_0 20400
+#define __CORDOVA_2_5_0 20500
 #define __CORDOVA_NA 99999      /* not available */
 
 /*
@@ -46,7 +47,7 @@
  #endif
  */
 #ifndef CORDOVA_VERSION_MIN_REQUIRED
-    #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_2_4_0
+    #define CORDOVA_VERSION_MIN_REQUIRED __CORDOVA_2_5_0
 #endif
 
 /*
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m b/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m
index 4cf5c82..22aca98 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCamera.m
@@ -232,66 +232,68 @@
     NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType];
     // IMAGE TYPE
     if ([mediaType isEqualToString:(NSString*)kUTTypeImage]) {
-        // get the image
-        UIImage* image = nil;
-        if (cameraPicker.allowsEditing && [info objectForKey:UIImagePickerControllerEditedImage]) {
-            image = [info objectForKey:UIImagePickerControllerEditedImage];
-        } else {
-            image = [info objectForKey:UIImagePickerControllerOriginalImage];
-        }
-
-        if (cameraPicker.saveToPhotoAlbum) {
-            UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
-        }
-
-        if (cameraPicker.correctOrientation) {
-            image = [self imageCorrectedForCaptureOrientation:image];
-        }
-
-        UIImage* scaledImage = nil;
-
-        if ((cameraPicker.targetSize.width > 0) && (cameraPicker.targetSize.height > 0)) {
-            // if cropToSize, resize image and crop to target size, otherwise resize to fit target without cropping
-            if (cameraPicker.cropToSize) {
-                scaledImage = [self imageByScalingAndCroppingForSize:image toSize:cameraPicker.targetSize];
-            } else {
-                scaledImage = [self imageByScalingNotCroppingForSize:image toSize:cameraPicker.targetSize];
-            }
-        }
-
-        NSData* data = nil;
-
-        if (cameraPicker.encodingType == EncodingTypePNG) {
-            data = UIImagePNGRepresentation(scaledImage == nil ? image : scaledImage);
-        } else {
-            data = UIImageJPEGRepresentation(scaledImage == nil ? image : scaledImage, cameraPicker.quality / 100.0f);
-        }
-
-        if (cameraPicker.returnType == DestinationTypeFileUri) {
-            // write to temp directory and return URI
-            // get the temp directory path
-            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
-            NSString* filePath;
-
-            int i = 1;
-            do {
-                filePath = [NSString stringWithFormat:@"%@/%@%03d.%@", docsPath, CDV_PHOTO_PREFIX, i++, cameraPicker.encodingType == EncodingTypePNG ? @"png":@"jpg"];
-            } while ([fileMgr fileExistsAtPath:filePath]);
-
-            // save file
-            if (![data writeToFile:filePath options:NSAtomicWrite error:&err]) {
-                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]];
-            } else {
-                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[[NSURL fileURLWithPath:filePath] absoluteString]];
-            }
-        } else if (cameraPicker.returnType == DestinationTypeNativeUri) {
+        if (cameraPicker.returnType == DestinationTypeNativeUri) {
             NSString* nativeUri = [(NSURL*)[info objectForKey:UIImagePickerControllerReferenceURL] absoluteString];
             result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:nativeUri];
         } else {
-            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[data base64EncodedString]];
+            // get the image
+            UIImage* image = nil;
+            if (cameraPicker.allowsEditing && [info objectForKey:UIImagePickerControllerEditedImage]) {
+                image = [info objectForKey:UIImagePickerControllerEditedImage];
+            } else {
+                image = [info objectForKey:UIImagePickerControllerOriginalImage];
+            }
+
+            if (cameraPicker.saveToPhotoAlbum) {
+                UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
+            }
+
+            if (cameraPicker.correctOrientation) {
+                image = [self imageCorrectedForCaptureOrientation:image];
+            }
+
+            UIImage* scaledImage = nil;
+
+            if ((cameraPicker.targetSize.width > 0) && (cameraPicker.targetSize.height > 0)) {
+                // if cropToSize, resize image and crop to target size, otherwise resize to fit target without cropping
+                if (cameraPicker.cropToSize) {
+                    scaledImage = [self imageByScalingAndCroppingForSize:image toSize:cameraPicker.targetSize];
+                } else {
+                    scaledImage = [self imageByScalingNotCroppingForSize:image toSize:cameraPicker.targetSize];
+                }
+            }
+
+            NSData* data = nil;
+
+            if (cameraPicker.encodingType == EncodingTypePNG) {
+                data = UIImagePNGRepresentation(scaledImage == nil ? image : scaledImage);
+            } else {
+                data = UIImageJPEGRepresentation(scaledImage == nil ? image : scaledImage, cameraPicker.quality / 100.0f);
+            }
+
+            if (cameraPicker.returnType == DestinationTypeFileUri) {
+                // write to temp directory and return URI
+                // get the temp directory path
+                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
+                NSString* filePath;
+
+                int i = 1;
+                do {
+                    filePath = [NSString stringWithFormat:@"%@/%@%03d.%@", docsPath, CDV_PHOTO_PREFIX, i++, cameraPicker.encodingType == EncodingTypePNG ? @"png":@"jpg"];
+                } while ([fileMgr fileExistsAtPath:filePath]);
+
+                // save file
+                if (![data writeToFile:filePath options:NSAtomicWrite error:&err]) {
+                    result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]];
+                } else {
+                    result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[[NSURL fileURLWithPath:filePath] absoluteString]];
+                }
+            } else {
+                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[data base64EncodedString]];
+            }
         }
     }
     // NOT IMAGE TYPE (MOVIE)
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCapture.m b/lib/cordova-ios/CordovaLib/Classes/CDVCapture.m
index 95c3f17..ed9f664 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCapture.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCapture.m
@@ -20,7 +20,6 @@
 #import "CDVCapture.h"
 #import "CDVJSON.h"
 #import "CDVAvailability.h"
-#import "CDVViewController.h"
 
 #define kW3CMediaFormatHeight @"height"
 #define kW3CMediaFormatWidth @"width"
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegate.h b/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegate.h
index 6b1dedd..e177c63 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegate.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegate.h
@@ -22,9 +22,12 @@
 
 @class CDVPlugin;
 @class CDVPluginResult;
+@class CDVWhitelist;
 
 @protocol CDVCommandDelegate <NSObject>
 
+@property (nonatomic, readonly) NSDictionary* settings;
+
 - (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.");
@@ -46,5 +49,7 @@
 - (void)runInBackground:(void (^)())block;
 // Returns the User-Agent of the associated UIWebView.
 - (NSString*)userAgent;
+// Returns whether the given URL passes the white-list.
+- (BOOL)URLIsWhitelisted:(NSURL*)url;
 
 @end
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegateImpl.m b/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegateImpl.m
index 8845e40..e399289 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegateImpl.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVCommandDelegateImpl.m
@@ -137,4 +137,15 @@
     return [_viewController userAgent];
 }
 
+- (BOOL)URLIsWhitelisted:(NSURL*)url
+{
+    return ![_viewController.whitelist schemeIsAllowed:[url scheme]] ||
+           [_viewController.whitelist URLIsAllowed:url];
+}
+
+- (NSDictionary*)settings
+{
+    return _viewController.settings;
+}
+
 @end
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.h b/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.h
index 0f4fa4c..7392580 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.h
@@ -22,8 +22,7 @@
 @property (nonatomic, readonly, strong) NSMutableDictionary* pluginsDict;
 @property (nonatomic, readonly, strong) NSMutableDictionary* settings;
 @property (nonatomic, readonly, strong) NSMutableArray* whitelistHosts;
+@property (nonatomic, readonly, strong) NSMutableArray* startupPluginNames;
 @property (nonatomic, readonly, strong) NSString* startPage;
 
-- (NSString*)getStartPage;
-
 @end
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.m b/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.m
index 3938b3e..6fd5913 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVConfigParser.m
@@ -24,21 +24,23 @@
 @property (nonatomic, readwrite, strong) NSMutableDictionary* pluginsDict;
 @property (nonatomic, readwrite, strong) NSMutableDictionary* settings;
 @property (nonatomic, readwrite, strong) NSMutableArray* whitelistHosts;
+@property (nonatomic, readwrite, strong) NSMutableArray* startupPluginNames;
 @property (nonatomic, readwrite, strong) NSString* startPage;
 
 @end
 
 @implementation CDVConfigParser
 
-@synthesize pluginsDict, settings, whitelistHosts, startPage;
+@synthesize pluginsDict, settings, whitelistHosts, startPage, startupPluginNames;
 
 - (id)init
 {
     self = [super init];
     if (self != nil) {
-        self.pluginsDict = [[NSMutableDictionary alloc] initWithCapacity:4];
-        self.settings = [[NSMutableDictionary alloc] initWithCapacity:4];
-        self.whitelistHosts = [[NSMutableArray alloc] initWithCapacity:1];
+        self.pluginsDict = [[NSMutableDictionary alloc] initWithCapacity:30];
+        self.settings = [[NSMutableDictionary alloc] initWithCapacity:30];
+        self.whitelistHosts = [[NSMutableArray alloc] initWithCapacity:30];
+        self.startupPluginNames = [[NSMutableArray alloc] initWithCapacity:8];
     }
     return self;
 }
@@ -46,13 +48,17 @@
 - (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName attributes:(NSDictionary*)attributeDict
 {
     if ([elementName isEqualToString:@"preference"]) {
-        [settings setObject:[attributeDict objectForKey:@"value"] forKey:[attributeDict objectForKey:@"name"]];
+        settings[attributeDict[@"name"]] = attributeDict[@"value"];
     } else if ([elementName isEqualToString:@"plugin"]) {
-        [pluginsDict setObject:[attributeDict objectForKey:@"value"] forKey:[attributeDict objectForKey:@"name"]];
+        NSString* name = [attributeDict[@"name"] lowercaseString];
+        pluginsDict[name] = attributeDict[@"value"];
+        if ([@"true" isEqualToString:attributeDict[@"onload"]]) {
+            [self.startupPluginNames addObject:name];
+        }
     } else if ([elementName isEqualToString:@"access"]) {
-        [whitelistHosts addObject:[attributeDict objectForKey:@"origin"]];
+        [whitelistHosts addObject:attributeDict[@"origin"]];
     } else if ([elementName isEqualToString:@"content"]) {
-        self.startPage = [attributeDict objectForKey:@"src"];
+        self.startPage = attributeDict[@"src"];
     }
 }
 
@@ -61,13 +67,4 @@
     NSAssert(NO, @"config.xml parse error line %d col %d", [parser lineNumber], [parser columnNumber]);
 }
 
-- (NSString*)getStartPage
-{
-    if (self.startPage != nil) {
-        return self.startPage;
-    } else {
-        return @"index.html";
-    }
-}
-
 @end
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVDevice.m b/lib/cordova-ios/CordovaLib/Classes/CDVDevice.m
index 46195e8..cc7ad89 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVDevice.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVDevice.m
@@ -58,6 +58,7 @@
     NSDictionary* temp = [CDVViewController getBundlePlist:@"Settings"];
 
     if ([temp respondsToSelector:@selector(JSONString)]) {
+        NSLog(@"Deprecation warning: window.Setting will be removed Aug 2013. Refer to https://issues.apache.org/jira/browse/CB-2433");
         NSString* js = [NSString stringWithFormat:@"window.Settings = %@;", [temp JSONString]];
         [self.commandDelegate evalJs:js];
     }
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFile.m b/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
index 11b2b77..d52405d 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFile.m
@@ -22,6 +22,9 @@
 #import "NSDictionary+Extensions.h"
 #import "CDVJSON.h"
 #import "NSData+Base64.h"
+#import <AssetsLibrary/ALAsset.h>
+#import <AssetsLibrary/ALAssetRepresentation.h>
+#import <AssetsLibrary/ALAssetsLibrary.h>
 #import <MobileCoreServices/MobileCoreServices.h>
 #import "CDVAvailability.h"
 #import "sys/xattr.h"
@@ -434,9 +437,9 @@
     // arguments are URL encoded
     NSString* fullPath = [command.arguments objectAtIndex:0];
 
-    // return unsupported result for assets-library URLs
+    // we don't (yet?) support getting the parent of an asset
     if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) {
-        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"remove not supported for assets-library URLs."];
+        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_READABLE_ERR];
         [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
         return;
     }
@@ -477,11 +480,33 @@
 {
     // arguments
     NSString* argPath = [command.arguments objectAtIndex:0];
+    __block CDVPluginResult* result = nil;
 
-    // return unsupported result for assets-library URLs
     if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) {
-        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"getMetadata not supported for assets-library URLs."];
-        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+        // 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!  Retrieve the metadata and send it off.
+                NSDate* date = [asset valueForProperty:ALAssetPropertyDate];
+                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDouble:[date timeIntervalSince1970] * 1000];
+                [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];
+            }
+        };
+        // TODO(maxw): Consider making this a class variable since it's the same every time.
+        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];
+        };
+
+        ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
+        [assetsLibrary assetForURL:[NSURL URLWithString:argPath] resultBlock:resultBlock failureBlock:failureBlock];
         return;
     }
 
@@ -489,7 +514,6 @@
 
     NSFileManager* fileMgr = [[NSFileManager alloc] init];
     NSError* __autoreleasing error = nil;
-    CDVPluginResult* result = nil;
 
     NSDictionary* fileAttribs = [fileMgr attributesOfItemAtPath:testPath error:&error];
 
@@ -501,7 +525,7 @@
     } 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;
         }
@@ -524,34 +548,29 @@
     // arguments
     NSString* filePath = [command.arguments objectAtIndex:0];
     NSDictionary* options = [command.arguments objectAtIndex:1 withDefault:nil];
-
-    // return unsupported result for assets-library URLs
-    if ([filePath hasPrefix:kCDVAssetsLibraryPrefix]) {
-        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"setMetadata not supported for assets-library URLs."];
-        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
-        return;
-    }
-
     CDVPluginResult* result = nil;
     BOOL ok = NO;
 
-    // we only care about this iCloud key for now.
-    // set to 1/true to skip backup, set to 0/false to back it up (effectively removing the attribute)
-    NSString* iCloudBackupExtendedAttributeKey = @"com.apple.MobileBackup";
-    id iCloudBackupExtendedAttributeValue = [options objectForKey:iCloudBackupExtendedAttributeKey];
+    // setMetadata doesn't make sense for asset library files
+    if (![filePath hasPrefix:kCDVAssetsLibraryPrefix]) {
+        // we only care about this iCloud key for now.
+        // set to 1/true to skip backup, set to 0/false to back it up (effectively removing the attribute)
+        NSString* iCloudBackupExtendedAttributeKey = @"com.apple.MobileBackup";
+        id iCloudBackupExtendedAttributeValue = [options objectForKey:iCloudBackupExtendedAttributeKey];
 
-    if ((iCloudBackupExtendedAttributeValue != nil) && [iCloudBackupExtendedAttributeValue isKindOfClass:[NSNumber class]]) {
-        if (IsAtLeastiOSVersion(@"5.1")) {
-            NSURL* url = [NSURL fileURLWithPath:filePath];
-            NSError* __autoreleasing error = nil;
+        if ((iCloudBackupExtendedAttributeValue != nil) && [iCloudBackupExtendedAttributeValue isKindOfClass:[NSNumber class]]) {
+            if (IsAtLeastiOSVersion(@"5.1")) {
+                NSURL* url = [NSURL fileURLWithPath:filePath];
+                NSError* __autoreleasing error = nil;
 
-            ok = [url setResourceValue:[NSNumber numberWithBool:[iCloudBackupExtendedAttributeValue boolValue]] forKey:NSURLIsExcludedFromBackupKey error:&error];
-        } else { // below 5.1 (deprecated - only really supported in 5.01)
-            u_int8_t value = [iCloudBackupExtendedAttributeValue intValue];
-            if (value == 0) { // remove the attribute (allow backup, the default)
-                ok = (removexattr([filePath fileSystemRepresentation], [iCloudBackupExtendedAttributeKey cStringUsingEncoding:NSUTF8StringEncoding], 0) == 0);
-            } else { // set the attribute (skip backup)
-                ok = (setxattr([filePath fileSystemRepresentation], [iCloudBackupExtendedAttributeKey cStringUsingEncoding:NSUTF8StringEncoding], &value, sizeof(value), 0, 0) == 0);
+                ok = [url setResourceValue:[NSNumber numberWithBool:[iCloudBackupExtendedAttributeValue boolValue]] forKey:NSURLIsExcludedFromBackupKey error:&error];
+            } else { // below 5.1 (deprecated - only really supported in 5.01)
+                u_int8_t value = [iCloudBackupExtendedAttributeValue intValue];
+                if (value == 0) { // remove the attribute (allow backup, the default)
+                    ok = (removexattr([filePath fileSystemRepresentation], [iCloudBackupExtendedAttributeKey cStringUsingEncoding:NSUTF8StringEncoding], 0) == 0);
+                } else { // set the attribute (skip backup)
+                    ok = (setxattr([filePath fileSystemRepresentation], [iCloudBackupExtendedAttributeKey cStringUsingEncoding:NSUTF8StringEncoding], &value, sizeof(value), 0, 0) == 0);
+                }
             }
         }
     }
@@ -570,26 +589,21 @@
  *	0 - NSString* fullPath
  *
  * returns NO_MODIFICATION_ALLOWED_ERR  if is top level directory or no permission to delete dir
- * returns INVALID_MODIFICATION_ERR if is dir and is not empty
+ * returns INVALID_MODIFICATION_ERR if is non-empty dir or asset library file
  * returns NOT_FOUND_ERR if file or dir is not found
 */
 - (void)remove:(CDVInvokedUrlCommand*)command
 {
     // arguments
     NSString* fullPath = [command.arguments objectAtIndex:0];
-
-    // return unsupported result for assets-library URLs
-    if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) {
-        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"remove not supported for assets-library URLs."];
-        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
-        return;
-    }
-
     CDVPluginResult* result = nil;
     CDVFileError errorCode = 0;  // !! 0 not currently defined
 
-    // error if try to remove top level (documents or tmp) dir
-    if ([fullPath isEqualToString:self.appDocsPath] || [fullPath isEqualToString:self.appTempPath]) {
+    // return error for assets-library URLs
+    if ([fullPath hasPrefix:kCDVAssetsLibraryPrefix]) {
+        errorCode = INVALID_MODIFICATION_ERR;
+    } else if ([fullPath isEqualToString:self.appDocsPath] || [fullPath isEqualToString:self.appTempPath]) {
+        // error if try to remove top level (documents or tmp) dir
         errorCode = NO_MODIFICATION_ALLOWED_ERR;
     } else {
         NSFileManager* fileMgr = [[NSFileManager alloc] init];
@@ -738,14 +752,7 @@
     // optional argument
     NSString* newName = ([arguments count] > 2) ? [arguments objectAtIndex:2] : [srcFullPath lastPathComponent];          // use last component from appPath if new name not provided
 
-    // return unsupported result for assets-library URLs
-    if ([srcFullPath hasPrefix:kCDVAssetsLibraryPrefix]) {
-        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"moveTo/copyTo not supported for assets-library URLs."];
-        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
-        return;
-    }
-
-    CDVPluginResult* result = nil;
+    __block CDVPluginResult* result = nil;
     CDVFileError errCode = 0;  // !! Currently 0 is not defined, use this to signal error !!
 
     /*NSString* destRootPath = nil;
@@ -762,12 +769,59 @@
         errCode = ENCODING_ERR;
     } else {
         NSString* newFullPath = [destRootPath stringByAppendingPathComponent:newName];
+        NSFileManager* fileMgr = [[NSFileManager alloc] init];
         if ([newFullPath isEqualToString:srcFullPath]) {
             // source and destination can not be the same
             errCode = INVALID_MODIFICATION_ERR;
-        } else {
-            NSFileManager* fileMgr = [[NSFileManager alloc] init];
+        } else if ([srcFullPath hasPrefix:kCDVAssetsLibraryPrefix]) {
+            if (bCopy) {
+                // Copying (as opposed to moving) an assets library file is okay.
+                // 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 try to copy it over.
+                        if (![fileMgr fileExistsAtPath:destRootPath]) {
+                            // The destination directory doesn't exist.
+                            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
+                            [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+                            return;
+                        } else if ([fileMgr fileExistsAtPath:newFullPath]) {
+                            // A file already exists at the destination path.
+                            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:PATH_EXISTS_ERR];
+                            [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+                            return;
+                        }
 
+                        // We're good to go!  Write the file to the new destination.
+                        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];
+                        [data writeToFile:newFullPath atomically:YES];
+                        result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self getDirectoryEntry:newFullPath isDirectory:NO]];
+                        [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];
+                };
+
+                ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
+                [assetsLibrary assetForURL:[NSURL URLWithString:srcFullPath] resultBlock:resultBlock failureBlock:failureBlock];
+                return;
+            } else {
+                // Moving an assets library file is not doable, since we can't remove it.
+                errCode = INVALID_MODIFICATION_ERR;
+            }
+        } else {
             BOOL bSrcIsDir = NO;
             BOOL bDestIsDir = NO;
             BOOL bNewIsDir = NO;
@@ -890,37 +944,67 @@
     // arguments
     NSString* argPath = [command.arguments objectAtIndex:0];
 
-    // return unsupported result for assets-library URLs
-    if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) {
-        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"getFileMetadata not supported for assets-library URLs."];
-        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
-        return;
-    }
-
-    CDVPluginResult* result = nil;
+    __block CDVPluginResult* result = nil;
 
     NSString* fullPath = argPath; // [self getFullPath: argPath];
 
     if (fullPath) {
-        NSFileManager* fileMgr = [[NSFileManager alloc] init];
-        BOOL bIsDir = NO;
-        // make sure it exists and is not a directory
-        BOOL bExists = [fileMgr fileExistsAtPath:fullPath isDirectory:&bIsDir];
-        if (!bExists || bIsDir) {
-            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
+        if ([fullPath 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!  Populate the dictionary and send it off.
+                    NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
+                    ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
+                    [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[assetRepresentation size]] forKey:@"size"];
+                    [fileInfo setObject:argPath forKey:@"fullPath"];
+                    NSString* filename = [assetRepresentation filename];
+                    [fileInfo setObject:filename forKey:@"name"];
+                    [fileInfo setObject:[self getMimeTypeFromPath:filename] forKey:@"type"];
+                    NSDate* creationDate = [asset valueForProperty:ALAssetPropertyDate];
+                    NSNumber* msDate = [NSNumber numberWithDouble:[creationDate timeIntervalSince1970] * 1000];
+                    [fileInfo setObject:msDate forKey:@"lastModifiedDate"];
+
+                    result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo];
+                    [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];
+            };
+
+            ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
+            [assetsLibrary assetForURL:[NSURL URLWithString:argPath] resultBlock:resultBlock failureBlock:failureBlock];
+            return;
         } else {
-            // create dictionary of file info
-            NSError* __autoreleasing error = nil;
-            NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:fullPath error:&error];
-            NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
-            [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[fileAttrs fileSize]] forKey:@"size"];
-            [fileInfo setObject:argPath forKey:@"fullPath"];
-            [fileInfo setObject:@"" forKey:@"type"];  // can't easily get the mimetype unless create URL, send request and read response so skipping
-            [fileInfo setObject:[argPath lastPathComponent] forKey:@"name"];
-            NSDate* modDate = [fileAttrs fileModificationDate];
-            NSNumber* msDate = [NSNumber numberWithDouble:[modDate timeIntervalSince1970] * 1000];
-            [fileInfo setObject:msDate forKey:@"lastModifiedDate"];
-            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo];
+            NSFileManager* fileMgr = [[NSFileManager alloc] init];
+            BOOL bIsDir = NO;
+            // make sure it exists and is not a directory
+            BOOL bExists = [fileMgr fileExistsAtPath:fullPath isDirectory:&bIsDir];
+            if (!bExists || bIsDir) {
+                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR];
+            } else {
+                // create dictionary of file info
+                NSError* __autoreleasing error = nil;
+                NSDictionary* fileAttrs = [fileMgr attributesOfItemAtPath:fullPath error:&error];
+                NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
+                [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[fileAttrs fileSize]] forKey:@"size"];
+                [fileInfo setObject:argPath forKey:@"fullPath"];
+                [fileInfo setObject:@"" forKey:@"type"];  // can't easily get the mimetype unless create URL, send request and read response so skipping
+                [fileInfo setObject:[argPath lastPathComponent] forKey:@"name"];
+                NSDate* modDate = [fileAttrs fileModificationDate];
+                NSNumber* msDate = [NSNumber numberWithDouble:[modDate timeIntervalSince1970] * 1000];
+                [fileInfo setObject:msDate forKey:@"lastModifiedDate"];
+                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo];
+            }
         }
     }
     if (!result) {
@@ -991,19 +1075,15 @@
         end = [[command.arguments objectAtIndex:3] integerValue];
     }
 
-    // return unsupported result for assets-library URLs
-    if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) {
-        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"readAsText not supported for assets-library URLs."];
-        [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 (!file) {
+    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 {
@@ -1054,18 +1134,41 @@
         end = [[command.arguments objectAtIndex:2] integerValue];
     }
 
-    // return unsupported result for assets-library URLs
-    if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) {
-        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"readAsDataURL not supported for assets-library URLs."];
-        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
-        return;
-    }
-
     CDVFileError errCode = ABORT_ERR;
-    CDVPluginResult* result = nil;
+    __block CDVPluginResult* result = nil;
 
     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];
+        };
+
+        ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
+        [assetsLibrary assetForURL:[NSURL URLWithString:argPath] resultBlock:resultBlock failureBlock:failureBlock];
+        return;
     } else {
         NSString* mimeType = [self getMimeTypeFromPath:argPath];
         if (!mimeType) {
@@ -1134,9 +1237,9 @@
     NSString* argPath = [command.arguments objectAtIndex:0];
     unsigned long long pos = (unsigned long long)[[command.arguments objectAtIndex:1] longLongValue];
 
-    // return unsupported result for assets-library URLs
+    // assets-library files can't be truncated
     if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) {
-        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"truncate not supported for assets-library URLs."];
+        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR];
         [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
         return;
     }
@@ -1181,9 +1284,9 @@
     NSString* argData = [arguments objectAtIndex:1];
     unsigned long long pos = (unsigned long long)[[arguments objectAtIndex:2] longLongValue];
 
-    // return unsupported result for assets-library URLs
+    // text can't be written into assets-library files
     if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) {
-        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"write not supported for assets-library URLs."];
+        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR];
         [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
         return;
     }
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
index 5392236..f96bb7d 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.h
@@ -50,7 +50,8 @@
 - (NSMutableDictionary*)createFileTransferError:(int)code
        AndSource                                   :(NSString*)source
        AndTarget                                   :(NSString*)target
-   AndHttpStatus                               :(int)httpStatus;
+   AndHttpStatus                               :(int)httpStatus
+         AndBody                                     :(NSString*)body;
 @property (readonly) NSMutableDictionary* activeTransfers;
 @end
 
@@ -64,6 +65,7 @@
 @property (nonatomic, copy) NSString* objectId;
 @property (nonatomic, copy) NSString* source;
 @property (nonatomic, copy) NSString* target;
+@property (nonatomic, copy) NSString* mimeType;
 @property (assign) int responseCode; // atomic
 @property (nonatomic, assign) NSInteger bytesTransfered;
 @property (nonatomic, assign) NSInteger bytesExpected;
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
index 8e05658..4ccdce6 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVFileTransfer.m
@@ -19,7 +19,10 @@
 
 #import "CDV.h"
 
-#include <CFNetwork/CFNetwork.h>
+#import <AssetsLibrary/ALAsset.h>
+#import <AssetsLibrary/ALAssetRepresentation.h>
+#import <AssetsLibrary/ALAssetsLibrary.h>
+#import <CFNetwork/CFNetwork.h>
 
 @interface CDVFileTransfer ()
 // Sets the requests headers for the request.
@@ -27,7 +30,7 @@
 // Creates a delegate to handle an upload.
 - (CDVFileTransferDelegate*)delegateForUploadCommand:(CDVInvokedUrlCommand*)command;
 // Creates an NSData* for the file for the given upload arguments.
-- (NSData*)fileDataForUploadCommand:(CDVInvokedUrlCommand*)command;
+- (void)fileDataForUploadCommand:(CDVInvokedUrlCommand*)command;
 @end
 
 // Buffer size to use for streaming uploads.
@@ -254,35 +257,60 @@
     return delegate;
 }
 
-- (NSData*)fileDataForUploadCommand:(CDVInvokedUrlCommand*)command
+- (void)fileDataForUploadCommand:(CDVInvokedUrlCommand*)command
 {
     NSString* target = (NSString*)[command.arguments objectAtIndex:0];
     NSError* __autoreleasing err = nil;
-    // Extract the path part out of a file: URL.
-    NSString* filePath = [target hasPrefix:@"/"] ? [target copy] : [[NSURL URLWithString:target] path];
 
-    // 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];
+    // 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) {
+            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* fileData = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
+                [self uploadData:fileData command:command];
+            } else {
+                // 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];
+            }
+        };
+        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];
+        };
 
-    if (err != nil) {
-        NSLog(@"Error opening file %@: %@", target, err);
+        ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
+        [assetsLibrary assetForURL:[NSURL URLWithString:target] resultBlock:resultBlock failureBlock:failureBlock];
+        return;
+    } else {
+        // Extract the path part out of a file: URL.
+        NSString* filePath = [target hasPrefix:@"/"] ? [target copy] : [[NSURL URLWithString:target] path];
+
+        // 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);
+        }
+        [self uploadData:fileData command:command];
     }
-    return fileData;
 }
 
 - (void)upload:(CDVInvokedUrlCommand*)command
 {
-    NSString* argPath = [command.arguments objectAtIndex:0];
-
-    // return unsupported result for assets-library URLs
-    if ([argPath hasPrefix:kCDVAssetsLibraryPrefix]) {
-        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"upload not supported for assets-library URLs."];
-        [self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
-        return;
-    }
-
     // fileData and req are split into helper functions to ease the unit testing of delegateForUpload.
-    NSData* fileData = [self fileDataForUploadCommand:command];
+    // First, get the file data.  This method will call `uploadData:command`.
+    [self fileDataForUploadCommand:command];
+}
+
+- (void)uploadData:(NSData*)fileData command:(CDVInvokedUrlCommand*)command
+{
     NSURLRequest* req = [self requestForUploadCommand:command fileData:fileData];
 
     if (req == nil) {
@@ -396,13 +424,15 @@
                                       AndSource:(NSString*)source
                                       AndTarget:(NSString*)target
                                   AndHttpStatus:(int)httpStatus
+                                        AndBody:(NSString*)body
 {
-    NSMutableDictionary* result = [NSMutableDictionary dictionaryWithCapacity:4];
+    NSMutableDictionary* result = [NSMutableDictionary dictionaryWithCapacity:5];
 
     [result setObject:[NSNumber numberWithInt:code] forKey:@"code"];
     [result setObject:source forKey:@"source"];
     [result setObject:target forKey:@"target"];
     [result setObject:[NSNumber numberWithInt:httpStatus] forKey:@"http_status"];
+    [result setObject:body forKey:@"body"];
     NSLog(@"FileTransferError %@", result);
 
     return result;
@@ -426,7 +456,8 @@
 - (void)connectionDidFinishLoading:(NSURLConnection*)connection
 {
     NSString* uploadResponse = nil;
-    BOOL downloadResponse;
+    NSString* downloadResponse = nil;
+    BOOL downloadWriteOK = NO;
     NSMutableDictionary* uploadResult;
     CDVPluginResult* result = nil;
     NSError* __autoreleasing error = nil;
@@ -437,9 +468,10 @@
     NSLog(@"File Transfer Finished with response code %d", self.responseCode);
 
     if (self.direction == CDV_TRANSFER_UPLOAD) {
+        uploadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
+
         if ((self.responseCode >= 200) && (self.responseCode < 300)) {
             // create dictionary to return FileUploadResult object
-            uploadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
             uploadResult = [NSMutableDictionary dictionaryWithCapacity:3];
             if (uploadResponse != nil) {
                 [uploadResult setObject:uploadResponse forKey:@"response"];
@@ -448,7 +480,7 @@
             [uploadResult setObject:[NSNumber numberWithInt:self.responseCode] forKey:@"responseCode"];
             result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:uploadResult];
         } else {
-            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode]];
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:uploadResponse]];
         }
     }
     if (self.direction == CDV_TRANSFER_DOWNLOAD) {
@@ -464,11 +496,12 @@
                     [[NSFileManager defaultManager] createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:nil];
                 }
 
-                downloadResponse = [self.responseData writeToFile:self.target options:NSDataWritingFileProtectionNone error:&error];
+                downloadWriteOK = [self.responseData writeToFile:self.target options:NSDataWritingFileProtectionNone error:&error];
 
-                if (downloadResponse == NO) {
+                if (downloadWriteOK == NO) {
                     // send our results back
-                    result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:INVALID_URL_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode]];
+                    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");
 
@@ -479,10 +512,13 @@
             }
             @catch(id exception) {
                 // jump back to main thread
-                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsDictionary:[command createFileTransferError:FILE_NOT_FOUND_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode]];
+                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]];
             }
         } else {
-            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode]];
+            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]];
         }
     }
 
@@ -494,6 +530,8 @@
 
 - (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
 {
+    self.mimeType = [response MIMEType];
+
     // required for iOS 4.3, for some reason; response is
     // a plain NSURLResponse, not the HTTP subclass
     if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
@@ -513,7 +551,8 @@
 
 - (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
 {
-    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode]];
+    NSString* body = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
+    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:body]];
 
     NSLog(@"File Transfer Error: %@", [error localizedDescription]);
 
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
index 45bf705..14671a5 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVInAppBrowser.m
@@ -19,7 +19,6 @@
 
 #import "CDVInAppBrowser.h"
 #import "CDVPluginResult.h"
-#import "CDVViewController.h"
 #import "CDVUserAgentUtil.h"
 
 #define    kInAppBrowserTargetSelf @"_self"
@@ -143,18 +142,7 @@
 
 - (void)openInCordovaWebView:(NSURL*)url withOptions:(NSString*)options
 {
-    BOOL passesWhitelist = YES;
-
-    if ([self.viewController isKindOfClass:[CDVViewController class]]) {
-        CDVViewController* vc = (CDVViewController*)self.viewController;
-        if ([vc.whitelist schemeIsAllowed:[url scheme]]) {
-            passesWhitelist = [vc.whitelist URLIsAllowed:url];
-        }
-    } else { // something went wrong, we can't get the whitelist
-        passesWhitelist = NO;
-    }
-
-    if (passesWhitelist) {
+    if ([self.commandDelegate URLIsWhitelisted:url]) {
         NSURLRequest* request = [NSURLRequest requestWithURL:url];
         [self.webView loadRequest:request];
     } else { // this assumes the InAppBrowser can be excepted from the white-list
@@ -374,15 +362,13 @@
 - (void)viewDidUnload
 {
     [self.webView loadHTMLString:nil baseURL:nil];
+    [CDVUserAgentUtil releaseLock:&_userAgentLockToken];
     [super viewDidUnload];
 }
 
 - (void)close
 {
-    if (_userAgentLockToken != 0) {
-        [CDVUserAgentUtil releaseLock:_userAgentLockToken];
-        _userAgentLockToken = 0;
-    }
+    [CDVUserAgentUtil releaseLock:&_userAgentLockToken];
 
     if ([self respondsToSelector:@selector(presentingViewController)]) {
         [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];
@@ -398,6 +384,7 @@
 - (void)navigateTo:(NSURL*)url
 {
     NSURLRequest* request = [NSURLRequest requestWithURL:url];
+
     _requestedURL = url;
 
     if (_userAgentLockToken != 0) {
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
index e5e3112..cc6613f 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.h
@@ -22,7 +22,7 @@
 #define kCDVLocalStorageErrorDomain @"kCDVLocalStorageErrorDomain"
 #define kCDVLocalStorageFileOperationError 1
 
-@interface CDVLocalStorage : CDVPlugin <UIWebViewDelegate>
+@interface CDVLocalStorage : CDVPlugin
 
 @property (nonatomic, readonly, strong) NSMutableArray* backupInfo;
 
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m
index 217f611..68175f1 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVLocalStorage.m
@@ -31,21 +31,13 @@
 
 @synthesize backupInfo, webviewDelegate;
 
-- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView settings:(NSDictionary*)classSettings
+- (void)pluginInitialize
 {
-    self = (CDVLocalStorage*)[super initWithWebView:theWebView settings:classSettings];
-    if (self) {
-        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResignActive)
-                                                     name:UIApplicationWillResignActiveNotification object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResignActive)
+                                                 name:UIApplicationWillResignActiveNotification object:nil];
+    BOOL cloudBackup = [@"cloud" isEqualToString:self.commandDelegate.settings[@"BackupWebStorage"]];
 
-        self.backupInfo = [[self class] createBackupInfoWithCloudBackup:[(NSString*)[classSettings objectForKey:@"backupType"] isEqualToString:@"cloud"]];
-
-        // over-ride current webview delegate (for restore reasons)
-        self.webviewDelegate = theWebView.delegate;
-        theWebView.delegate = self;
-    }
-
-    return self;
+    self.backupInfo = [[self class] createBackupInfoWithCloudBackup:cloudBackup];
 }
 
 #pragma mark -
@@ -411,37 +403,9 @@
     [self onResignActive];
 }
 
-#pragma mark -
-#pragma mark UIWebviewDelegate implementation and forwarding
-
-- (void)webViewDidStartLoad:(UIWebView*)theWebView
+- (void)onReset
 {
     [self restore:nil];
-
-    return [self.webviewDelegate webViewDidStartLoad:theWebView];
-}
-
-- (void)webViewDidFinishLoad:(UIWebView*)theWebView
-{
-    return [self.webviewDelegate webViewDidFinishLoad:theWebView];
-}
-
-- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error
-{
-    return [self.webviewDelegate webView:theWebView didFailLoadWithError:error];
-}
-
-- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
-{
-    return [self.webviewDelegate webView:theWebView shouldStartLoadWithRequest:request navigationType:navigationType];
-}
-
-#pragma mark -
-#pragma mark Over-rides
-
-- (void)dealloc
-{
-    [[NSNotificationCenter defaultCenter] removeObserver:self];   // this will remove all notification unless added using addObserverForName:object:queue:usingBlock:
 }
 
 @end
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m b/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m
index 9814f35..07af30e 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVLocation.m
@@ -18,7 +18,6 @@
  */
 
 #import "CDVLocation.h"
-#import "CDVViewController.h"
 #import "NSArray+Comparisons.h"
 
 #pragma mark Constants
@@ -477,17 +476,8 @@
 // helper method to check the orientation and start updating headings
 - (void)startHeadingWithFilter:(CLLocationDegrees)filter
 {
-    if ([self.locationManager respondsToSelector:@selector(headingOrientation)]) {
-        UIDeviceOrientation currentOrientation = [[UIDevice currentDevice] orientation];
-        if (currentOrientation != UIDeviceOrientationUnknown) {
-            CDVViewController* cdvViewController = (CDVViewController*)self.viewController;
-
-            if ([cdvViewController supportsOrientation:currentOrientation]) {
-                self.locationManager.headingOrientation = (CLDeviceOrientation)currentOrientation;
-                // FYI UIDeviceOrientation and CLDeviceOrientation enums are currently the same
-            }
-        }
-    }
+    // FYI UIDeviceOrientation and CLDeviceOrientation enums are currently the same
+    self.locationManager.headingOrientation = (CLDeviceOrientation)self.viewController.interfaceOrientation;
     self.locationManager.headingFilter = filter;
     [self.locationManager startUpdatingHeading];
     self.headingData.headingStatus = HEADINGSTARTING;
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h b/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h
index 8c59a2b..f5b50eb 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.h
@@ -23,6 +23,7 @@
 #import "NSMutableArray+QueueAdditions.h"
 #import "CDVCommandDelegate.h"
 
+#define CDVPageDidLoadNotification @"CDVPageDidLoadNotification"
 #define CDVPluginHandleOpenURLNotification @"CDVPluginHandleOpenURLNotification"
 #define CDVPluginResetNotification @"CDVPluginResetNotification"
 #define CDVLocalNotification @"CDVLocalNotification"
@@ -30,14 +31,13 @@
 @interface CDVPlugin : NSObject {}
 
 @property (nonatomic, weak) UIWebView* webView;
-@property (nonatomic, strong) NSDictionary* settings;
 @property (nonatomic, weak) UIViewController* viewController;
 @property (nonatomic, weak) id <CDVCommandDelegate> commandDelegate;
 
 @property (readonly, assign) BOOL hasPendingOperation;
 
-- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView settings:(NSDictionary*)classSettings;
 - (CDVPlugin*)initWithWebView:(UIWebView*)theWebView;
+- (void)pluginInitialize;
 
 - (void)handleOpenURL:(NSNotification*)notification;
 - (void)onAppTerminate;
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.m b/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.m
index 53023c7..a42d241 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVPlugin.m
@@ -26,16 +26,12 @@
 @end
 
 @implementation CDVPlugin
-@synthesize webView, settings, viewController, commandDelegate, hasPendingOperation;
+@synthesize webView, viewController, commandDelegate, hasPendingOperation;
 
+// Do not override these methods. Use pluginInitialize instead.
 - (CDVPlugin*)initWithWebView:(UIWebView*)theWebView settings:(NSDictionary*)classSettings
 {
-    self = [self initWithWebView:theWebView];
-    if (self) {
-        self.settings = classSettings;
-        self.hasPendingOperation = NO;
-    }
-    return self;
+    return [self initWithWebView:theWebView];
 }
 
 - (CDVPlugin*)initWithWebView:(UIWebView*)theWebView
@@ -48,26 +44,29 @@
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onReset) name:CDVPluginResetNotification object:nil];
 
         self.webView = theWebView;
-
-        // You can listen to more app notifications, see:
-        // http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006728-CH3-DontLinkElementID_4
-
-        /*
-         // NOTE: if you want to use these, make sure you uncomment the corresponding notification handler
-
-         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onPause) name:UIApplicationDidEnterBackgroundNotification object:nil];
-         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResume) name:UIApplicationWillEnterForegroundNotification object:nil];
-         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationWillChange) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
-         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationDidChange) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
-         
-         // Added in 2.3.0+
-         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveLocalNotification:) name:CDVLocalNotification object:nil]; 
-         
-         */
     }
     return self;
 }
 
+- (void)pluginInitialize
+{
+    // You can listen to more app notifications, see:
+    // http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIApplication_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40006728-CH3-DontLinkElementID_4
+
+    // NOTE: if you want to use these, make sure you uncomment the corresponding notification handler
+
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onPause) name:UIApplicationDidEnterBackgroundNotification object:nil];
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResume) name:UIApplicationWillEnterForegroundNotification object:nil];
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationWillChange) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
+    // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationDidChange) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
+
+    // Added in 2.3.0
+    // [[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];
+}
+
 - (void)dispose
 {
     viewController = nil;
@@ -140,9 +139,9 @@
 }
 
 // default implementation does nothing, ideally, we are not registered for notification if we aren't going to do anything.
-//- (void)didReceiveLocalNotification:(NSNotification *)notification
-//{    
+// - (void)didReceiveLocalNotification:(NSNotification *)notification
+// {
 //    // UILocalNotification* localNotification = [notification object]; // get the payload as a LocalNotification
-//}
+// }
 
 @end
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVSound.h b/lib/cordova-ios/CordovaLib/Classes/CDVSound.h
index 6551621..8dcf98e 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVSound.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVSound.h
@@ -98,7 +98,13 @@
 - (BOOL)hasAudioSession;
 
 // helper methods
-- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId;
+- (NSURL*)urlForRecording:(NSString*)resourcePath;
+- (NSURL*)urlForPlaying:(NSString*)resourcePath;
+- (NSURL*)urlForResource:(NSString*)resourcePath CDV_DEPRECATED(2.5, "Use specific api for playing or recording");
+
+- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId CDV_DEPRECATED(2.5, "Use updated audioFileForResource api");
+
+- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId doValidation:(BOOL)bValidate forRecording:(BOOL)bRecord;
 - (BOOL)prepareToPlay:(CDVAudioFile*)audioFile withId:(NSString*)mediaId;
 - (NSString*)createMediaErrorWithCode:(CDVMediaError)code message:(NSString*)message;
 
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVSound.m b/lib/cordova-ios/CordovaLib/Classes/CDVSound.m
index e6f729a..99515d7 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVSound.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVSound.m
@@ -18,20 +18,18 @@
  */
 
 #import "CDVSound.h"
-#import "CDVViewController.h"
 #import "NSArray+Comparisons.h"
 #import "CDVJSON.h"
 
 #define DOCUMENTS_SCHEME_PREFIX @"documents://"
 #define HTTP_SCHEME_PREFIX @"http://"
 #define HTTPS_SCHEME_PREFIX @"https://"
+#define RECORDING_WAV @"wav"
 
 @implementation CDVSound
 
 @synthesize soundCache, avSession;
 
-// Maps a url for a resource path
-// "Naked" resource paths are assumed to be from the www folder as its base
 - (NSURL*)urlForResource:(NSString*)resourcePath
 {
     NSURL* resourceURL = nil;
@@ -44,7 +42,8 @@
         NSLog(@"Will use resource '%@' from the Internet.", resourcePath);
         resourceURL = [NSURL URLWithString:resourcePath];
     } else if ([resourcePath hasPrefix:DOCUMENTS_SCHEME_PREFIX]) {
-        filePath = [resourcePath stringByReplacingOccurrencesOfString:DOCUMENTS_SCHEME_PREFIX withString:[NSString stringWithFormat:@"%@/", [CDVViewController applicationDocumentsDirectory]]];
+        NSString* docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
+        filePath = [resourcePath stringByReplacingOccurrencesOfString:DOCUMENTS_SCHEME_PREFIX withString:[NSString stringWithFormat:@"%@/", docsPath]];
         NSLog(@"Will use resource '%@' from the documents folder with path = %@", resourcePath, filePath);
     } else {
         // attempt to find file path in www directory
@@ -71,9 +70,101 @@
     return resourceURL;
 }
 
-// Creates or gets the cached audio file resource object
+// Maps a url for a resource path for recording
+- (NSURL*)urlForRecording:(NSString*)resourcePath
+{
+    NSURL* resourceURL = nil;
+    NSString* filePath = nil;
+    NSString* docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
+
+    // first check for correct extension
+    if ([[resourcePath pathExtension] caseInsensitiveCompare:RECORDING_WAV] != NSOrderedSame) {
+        resourceURL = nil;
+        NSLog(@"Resource for recording must have %@ extension", RECORDING_WAV);
+    } else if ([resourcePath hasPrefix:DOCUMENTS_SCHEME_PREFIX]) {
+        // try to find Documents:// resources
+        filePath = [resourcePath stringByReplacingOccurrencesOfString:DOCUMENTS_SCHEME_PREFIX withString:[NSString stringWithFormat:@"%@/", docsPath]];
+        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];
+        BOOL isTmp = [resourcePath rangeOfString:tmpPath].location != NSNotFound;
+        BOOL isDoc = [resourcePath rangeOfString:docsPath].location != NSNotFound;
+        if (!isTmp && !isDoc) {
+            // put in temp dir
+            filePath = [NSString stringWithFormat:@"%@/%@", tmpPath, resourcePath];
+        } else {
+            filePath = resourcePath;
+        }
+    }
+
+    if (filePath != nil) {
+        // create resourceURL
+        resourceURL = [NSURL fileURLWithPath:filePath];
+    }
+    return resourceURL;
+}
+
+// Maps a url for a resource path for playing
+// "Naked" resource paths are assumed to be from the www folder as its base
+- (NSURL*)urlForPlaying:(NSString*)resourcePath
+{
+    NSURL* resourceURL = nil;
+    NSString* filePath = nil;
+
+    // first try to find HTTP:// or Documents:// resources
+
+    if ([resourcePath hasPrefix:HTTP_SCHEME_PREFIX] || [resourcePath hasPrefix:HTTPS_SCHEME_PREFIX]) {
+        // if it is a http url, use it
+        NSLog(@"Will use resource '%@' from the Internet.", resourcePath);
+        resourceURL = [NSURL URLWithString:resourcePath];
+    } else if ([resourcePath hasPrefix:DOCUMENTS_SCHEME_PREFIX]) {
+        NSString* docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
+        filePath = [resourcePath stringByReplacingOccurrencesOfString:DOCUMENTS_SCHEME_PREFIX withString:[NSString stringWithFormat:@"%@/", docsPath]];
+        NSLog(@"Will use resource '%@' from the documents folder with path = %@", resourcePath, filePath);
+    } else {
+        // attempt to find file path in www directory or LocalFileSystem.TEMPORARY directory
+        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];
+            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;
+                NSLog(@"Will attempt to use file resource from LocalFileSystem.TEMPORARY directory");
+            } else {
+                // attempt to use path provided
+                filePath = resourcePath;
+                NSLog(@"Will attempt to use file resource '%@'", filePath);
+            }
+        } else {
+            NSLog(@"Found resource '%@' in the web folder.", filePath);
+        }
+    }
+    // check that file exists for all but HTTP_SHEME_PREFIX
+    if (filePath != nil) {
+        // create resourceURL
+        resourceURL = [NSURL fileURLWithPath:filePath];
+        // try to access file
+        NSFileManager* fMgr = [NSFileManager defaultManager];
+        if (![fMgr fileExistsAtPath:filePath]) {
+            resourceURL = nil;
+            NSLog(@"Unknown resource '%@'", resourcePath);
+        }
+    }
+
+    return resourceURL;
+}
+
 - (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId
 {
+    // will maintain backwards compatibility with original implementation
+    return [self audioFileForResource:resourcePath withId:mediaId doValidation:YES forRecording:NO];
+}
+
+// Creates or gets the cached audio file resource object
+- (CDVAudioFile*)audioFileForResource:(NSString*)resourcePath withId:(NSString*)mediaId doValidation:(BOOL)bValidate forRecording:(BOOL)bRecord
+{
     BOOL bError = NO;
     CDVMediaError errcode = MEDIA_ERR_NONE_SUPPORTED;
     NSString* errMsg = @"";
@@ -88,31 +179,37 @@
     }
     if (audioFile == nil) {
         // validate resourcePath and create
-
         if ((resourcePath == nil) || ![resourcePath isKindOfClass:[NSString class]] || [resourcePath isEqualToString:@""]) {
             bError = YES;
             errcode = MEDIA_ERR_ABORTED;
             errMsg = @"invalid media src argument";
         } else {
-            resourceURL = [self urlForResource:resourcePath];
+            audioFile = [[CDVAudioFile alloc] init];
+            audioFile.resourcePath = resourcePath;
+            audioFile.resourceURL = nil;  // validate resourceURL when actually play or record
+            [[self soundCache] setObject:audioFile forKey:mediaId];
         }
-
+    }
+    if (bValidate && (audioFile.resourceURL == nil)) {
+        if (bRecord) {
+            resourceURL = [self urlForRecording:resourcePath];
+        } else {
+            resourceURL = [self urlForPlaying:resourcePath];
+        }
         if (resourceURL == nil) {
             bError = YES;
             errcode = MEDIA_ERR_ABORTED;
             errMsg = [NSString stringWithFormat:@"Cannot use audio file from resource '%@'", resourcePath];
-        }
-        if (bError) {
-            // jsString = [NSString stringWithFormat: @"%@(\"%@\",%d,%d);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, errcode];
-            jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:errcode message:errMsg]];
-            [self.commandDelegate evalJs:jsString];
         } else {
-            audioFile = [[CDVAudioFile alloc] init];
-            audioFile.resourcePath = resourcePath;
             audioFile.resourceURL = resourceURL;
-            [[self soundCache] setObject:audioFile forKey:mediaId];
         }
     }
+
+    if (bError) {
+        jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:errcode message:errMsg]];
+        [self.commandDelegate evalJs:jsString];
+    }
+
     return audioFile;
 }
 
@@ -150,7 +247,7 @@
     NSString* mediaId = [command.arguments objectAtIndex:0];
     NSString* resourcePath = [command.arguments objectAtIndex:1];
 
-    CDVAudioFile* audioFile = [self audioFileForResource:resourcePath withId:mediaId];
+    CDVAudioFile* audioFile = [self audioFileForResource:resourcePath withId:mediaId doValidation:NO forRecording:NO];
 
     if (audioFile == nil) {
         NSString* errorMessage = [NSString stringWithFormat:@"Failed to initialize Media file with path %@", resourcePath];
@@ -194,9 +291,8 @@
     BOOL bError = NO;
     NSString* jsString = nil;
 
-    CDVAudioFile* audioFile = [self audioFileForResource:resourcePath withId:mediaId];
-
-    if (audioFile != nil) {
+    CDVAudioFile* audioFile = [self audioFileForResource:resourcePath withId:mediaId doValidation:YES forRecording:NO];
+    if ((audioFile != nil) && (audioFile.resourceURL != nil)) {
         if (audioFile.player == nil) {
             bError = [self prepareToPlay:audioFile withId:mediaId];
         }
@@ -275,7 +371,12 @@
     if ([resourceURL isFileURL]) {
         audioFile.player = [[CDVAudioPlayer alloc] initWithContentsOfURL:resourceURL error:&playerError];
     } else {
-        NSURLRequest* request = [NSURLRequest requestWithURL:resourceURL];
+        NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:resourceURL];
+        NSString* userAgent = [self.commandDelegate userAgent];
+        if (userAgent) {
+            [request setValue:userAgent forHTTPHeaderField:@"User-Agent"];
+        }
+
         NSURLResponse* __autoreleasing response = nil;
         NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&playerError];
         if (playerError) {
@@ -412,11 +513,11 @@
 #pragma unused(callbackId)
 
     NSString* mediaId = [command.arguments objectAtIndex:0];
-    CDVAudioFile* audioFile = [self audioFileForResource:[command.arguments objectAtIndex:1] withId:mediaId];
+    CDVAudioFile* audioFile = [self audioFileForResource:[command.arguments objectAtIndex:1] withId:mediaId doValidation:YES forRecording:YES];
     NSString* jsString = nil;
     NSString* errorMsg = @"";
 
-    if (audioFile != nil) {
+    if ((audioFile != nil) && (audioFile.resourceURL != nil)) {
         NSError* __autoreleasing error = nil;
 
         if (audioFile.recorder != nil) {
@@ -463,9 +564,9 @@
             jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMsg]];
         }
     } else {
-        // file does not exist
-        NSLog(@"Could not start recording audio, file '%@' does not exist.", audioFile.resourcePath);
-        jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:@"File to record to does not exist"]];
+        // file did not validate
+        NSString* errorMsg = [NSString stringWithFormat:@"Could not record audio at '%@'", audioFile.resourcePath];
+        jsString = [NSString stringWithFormat:@"%@(\"%@\",%d,%@);", @"cordova.require('cordova/plugin/Media').onStatus", mediaId, MEDIA_ERROR, [self createMediaErrorWithCode:MEDIA_ERR_ABORTED message:errorMsg]];
     }
     if (jsString) {
         [self.commandDelegate evalJs:jsString];
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.h b/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.h
index b0d8615..a0868a0 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.h
@@ -20,7 +20,11 @@
 #import <Foundation/Foundation.h>
 #import "CDVPlugin.h"
 
-@interface CDVSplashScreen : CDVPlugin {}
+@interface CDVSplashScreen : CDVPlugin {
+    UIActivityIndicatorView* _activityView;
+    UIImageView* _imageView;
+    UIView* _parentView;
+}
 
 - (void)show:(CDVInvokedUrlCommand*)command;
 - (void)hide:(CDVInvokedUrlCommand*)command;
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m b/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m
index 2512328..cba1b53 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVSplashScreen.m
@@ -18,32 +18,157 @@
  */
 
 #import "CDVSplashScreen.h"
-#import "CDVViewController.h"
+
+#define kSplashScreenStateShow 0
+#define kSplashScreenStateHide 1
+
+#define kSplashScreenDurationDefault 0.25f
 
 @implementation CDVSplashScreen
 
-- (void)__show:(BOOL)show
+- (void)pluginInitialize
 {
-    // Legacy support - once deprecated classes removed, clean this up
-    id <UIApplicationDelegate> delegate = [[UIApplication sharedApplication] delegate];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pageDidLoad) name:CDVPageDidLoadNotification object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onOrientationWillChange:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
 
-    if ([delegate respondsToSelector:@selector(viewController)]) {
-        id vc = [delegate performSelector:@selector(viewController)];
-        if ([vc isKindOfClass:[CDVViewController class]]) {
-            ((CDVViewController*)vc).imageView.hidden = !show;
-            ((CDVViewController*)vc).activityView.hidden = !show;
-        }
-    }
+    [self show:nil];
 }
 
 - (void)show:(CDVInvokedUrlCommand*)command
 {
-    [self __show:YES];
+    [self updateSplashScreenWithState:kSplashScreenStateShow];
 }
 
 - (void)hide:(CDVInvokedUrlCommand*)command
 {
-    [self __show:NO];
+    [self updateSplashScreenWithState:kSplashScreenStateHide];
+}
+
+- (void)pageDidLoad
+{
+    id autoHideSplashScreenValue = [self.commandDelegate.settings objectForKey:@"AutoHideSplashScreen"];
+
+    // if value is missing, default to yes
+    if ((autoHideSplashScreenValue == nil) || [autoHideSplashScreenValue boolValue]) {
+        [self hide:nil];
+    }
+}
+
+- (void)onOrientationWillChange:(NSNotification*)notification
+{
+    if (_imageView != nil) {
+        UIInterfaceOrientation orientation = [notification.userInfo[UIApplicationStatusBarOrientationUserInfoKey] intValue];
+        [self updateSplashImageForOrientation:orientation];
+    }
+}
+
+- (void)createViews
+{
+    /*
+     * The Activity View is the top spinning throbber in the status/battery bar. We init it with the default Grey Style.
+     *
+     *     whiteLarge = UIActivityIndicatorViewStyleWhiteLarge
+     *     white      = UIActivityIndicatorViewStyleWhite
+     *     gray       = UIActivityIndicatorViewStyleGray
+     *
+     */
+    NSString* topActivityIndicator = [self.commandDelegate.settings objectForKey:@"TopActivityIndicator"];
+    UIActivityIndicatorViewStyle topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray;
+
+    if ([topActivityIndicator isEqualToString:@"whiteLarge"]) {
+        topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhiteLarge;
+    } else if ([topActivityIndicator isEqualToString:@"white"]) {
+        topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhite;
+    } else if ([topActivityIndicator isEqualToString:@"gray"]) {
+        topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray;
+    }
+
+    _activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:topActivityIndicatorStyle];
+    _activityView.tag = 2;
+    _activityView.center = self.viewController.view.center;
+    [_activityView startAnimating];
+
+    _imageView = [[UIImageView alloc] init];
+    [self.viewController.view addSubview:_imageView];
+    [self.viewController.view.superview addSubview:_activityView];
+    [self.viewController.view.superview layoutSubviews];
+}
+
+- (void)updateSplashImageForOrientation:(UIInterfaceOrientation)orientation
+{
+    // IPHONE (default)
+    NSString* 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";
+
+        if (orientation == UIInterfaceOrientationLandscapeLeft) {
+            imageName = @"Default-Landscape.png"; // @"Default-LandscapeLeft.png";
+        } else if (orientation == UIInterfaceOrientationLandscapeRight) {
+            imageName = @"Default-Landscape.png"; // @"Default-LandscapeRight.png";
+        }
+    }
+
+    _imageView.image = [UIImage imageNamed:imageName];
+    _imageView.frame = CGRectMake(0, 0, _imageView.image.size.width, _imageView.image.size.height);
+}
+
+- (void)updateSplashScreenWithState:(int)state
+{
+    float toAlpha = state == kSplashScreenStateShow ? 1.0f : 0.0f;
+    BOOL hidden = state == kSplashScreenStateShow ? NO : YES;
+
+    id fadeSplashScreenValue = [self.commandDelegate.settings objectForKey:@"FadeSplashScreen"];
+    id fadeSplashScreenDuration = [self.commandDelegate.settings objectForKey:@"FadeSplashScreenDuration"];
+
+    float fadeDuration = fadeSplashScreenDuration == nil ? kSplashScreenDurationDefault : [fadeSplashScreenDuration floatValue];
+
+    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];
+        }
+
+        [UIView transitionWithView:self.viewController.view
+                          duration:fadeDuration
+                           options:UIViewAnimationOptionTransitionNone
+                        animations:^(void) {
+                [_imageView setAlpha:toAlpha];
+                [_activityView setAlpha:toAlpha];
+            }
+                        completion:^(BOOL finished) {
+                if (state == kSplashScreenStateHide) {
+                    // Clean-up resources.
+                    [_imageView removeFromSuperview];
+                    [_activityView removeFromSuperview];
+                    _imageView = nil;
+                    _activityView = nil;
+                }
+            }];
+    }
 }
 
 @end
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.m b/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.m
index a645288..1959c77 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVURLProtocol.m
@@ -17,14 +17,17 @@
  under the License.
  */
 
+#import <AssetsLibrary/ALAsset.h>
+#import <AssetsLibrary/ALAssetRepresentation.h>
+#import <AssetsLibrary/ALAssetsLibrary.h>
+#import <MobileCoreServices/MobileCoreServices.h>
 #import "CDVURLProtocol.h"
 #import "CDVCommandQueue.h"
 #import "CDVWhitelist.h"
 #import "CDVViewController.h"
+#import "CDVFile.h"
 
 @interface CDVHTTPURLResponse : NSHTTPURLResponse
-- (id)initWithUnauthorizedURL:(NSURL*)url;
-- (id)initWithBlankResponse:(NSURL*)url;
 @property (nonatomic) NSInteger statusCode;
 @end
 
@@ -106,7 +109,9 @@
     NSURL* theUrl = [theRequest URL];
     CDVViewController* viewController = viewControllerForRequest(theRequest);
 
-    if (viewController != nil) {
+    if ([[theUrl absoluteString] hasPrefix:kCDVAssetsLibraryPrefix]) {
+        return YES;
+    } else if (viewController != nil) {
         if ([[theUrl path] isEqualToString:@"/!gap_exec"]) {
             NSString* queuedCommandsJSON = [theRequest valueForHTTPHeaderField:@"cmds"];
             NSString* requestId = [theRequest valueForHTTPHeaderField:@"rc"];
@@ -151,21 +156,35 @@
     NSURL* url = [[self request] URL];
 
     if ([[url path] isEqualToString:@"/!gap_exec"]) {
-        CDVHTTPURLResponse* response = [[CDVHTTPURLResponse alloc] initWithBlankResponse:url];
-        [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
-        [[self client] URLProtocolDidFinishLoading:self];
+        [self sendResponseWithResponseCode:200 data:nil mimeType:nil];
+        return;
+    } else if ([[url absoluteString] hasPrefix:kCDVAssetsLibraryPrefix]) {
+        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]);
+                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];
+            } else {
+                // Retrieving the asset failed for some reason.  Send an error.
+                [self sendResponseWithResponseCode:404 data:nil mimeType:nil];
+            }
+        };
+        ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) {
+            // Retrieving the asset failed for some reason.  Send an error.
+            [self sendResponseWithResponseCode:401 data:nil mimeType:nil];
+        };
+
+        ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
+        [assetsLibrary assetForURL:url resultBlock:resultBlock failureBlock:failureBlock];
         return;
     }
 
     NSString* body = [gWhitelist errorStringForURL:url];
-
-    CDVHTTPURLResponse* response = [[CDVHTTPURLResponse alloc] initWithUnauthorizedURL:url];
-
-    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
-
-    [[self client] URLProtocol:self didLoadData:[body dataUsingEncoding:NSASCIIStringEncoding]];
-
-    [[self client] URLProtocolDidFinishLoading:self];
+    [self sendResponseWithResponseCode:401 data:[body dataUsingEncoding:NSASCIIStringEncoding] mimeType:nil];
 }
 
 - (void)stopLoading
@@ -178,29 +197,31 @@
     return NO;
 }
 
+- (void)sendResponseWithResponseCode:(NSInteger)statusCode data:(NSData*)data mimeType:(NSString*)mimeType
+{
+    if (mimeType == nil) {
+        mimeType = @"text/plain";
+    }
+    NSString* encodingName = [@"text/plain" isEqualToString:mimeType] ? @"UTF-8" : nil;
+    CDVHTTPURLResponse* response =
+        [[CDVHTTPURLResponse alloc] initWithURL:[[self request] URL]
+                                       MIMEType:mimeType
+                          expectedContentLength:[data length]
+                               textEncodingName:encodingName];
+    response.statusCode = statusCode;
+
+    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
+    if (data != nil) {
+        [[self client] URLProtocol:self didLoadData:data];
+    }
+    [[self client] URLProtocolDidFinishLoading:self];
+}
+
 @end
 
 @implementation CDVHTTPURLResponse
 @synthesize statusCode;
 
-- (id)initWithUnauthorizedURL:(NSURL*)url
-{
-    self = [super initWithURL:url MIMEType:@"text/plain" expectedContentLength:-1 textEncodingName:@"UTF-8"];
-    if (self) {
-        self.statusCode = 401;
-    }
-    return self;
-}
-
-- (id)initWithBlankResponse:(NSURL*)url
-{
-    self = [super initWithURL:url MIMEType:@"text/plain" expectedContentLength:-1 textEncodingName:@"UTF-8"];
-    if (self) {
-        self.statusCode = 200;
-    }
-    return self;
-}
-
 - (NSDictionary*)allHeaderFields
 {
     return nil;
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.h b/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.h
index 662b674..4de382f 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.h
@@ -22,6 +22,6 @@
 @interface CDVUserAgentUtil : NSObject
 + (NSString*)originalUserAgent;
 + (void)acquireLock:(void (^)(NSInteger lockToken))block;
-+ (void)releaseLock:(NSInteger)lockToken;
++ (void)releaseLock:(NSInteger*)lockToken;
 + (void)setUserAgent:(NSString*)value lockToken:(NSInteger)lockToken;
 @end
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.m b/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.m
index e2baef0..5c43c51 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVUserAgentUtil.m
@@ -84,11 +84,14 @@
     }
 }
 
-+ (void)releaseLock:(NSInteger)lockToken
++ (void)releaseLock:(NSInteger*)lockToken
 {
-    NSAssert(gCurrentLockToken == lockToken, @"Got token %d, expected %d", lockToken, gCurrentLockToken);
+    if (*lockToken == 0) {
+        return;
+    }
+    NSAssert(gCurrentLockToken == *lockToken, @"Got token %d, expected %d", *lockToken, gCurrentLockToken);
 
-    VerboseLog(@"Released lock %d", lockToken);
+    VerboseLog(@"Released lock %d", *lockToken);
     if ([gPendingSetUserAgentBlocks count] > 0) {
         void (^block)() = [gPendingSetUserAgentBlocks objectAtIndex:0];
         [gPendingSetUserAgentBlocks removeObjectAtIndex:0];
@@ -98,6 +101,7 @@
     } else {
         gCurrentLockToken = 0;
     }
+    *lockToken = 0;
 }
 
 + (void)setUserAgent:(NSString*)value lockToken:(NSInteger)lockToken
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVViewController.h b/lib/cordova-ios/CordovaLib/Classes/CDVViewController.h
index ed6f7fc..82e22f6 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVViewController.h
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVViewController.h
@@ -40,14 +40,11 @@
 
 @property (nonatomic, readonly, strong) NSMutableDictionary* pluginObjects;
 @property (nonatomic, readonly, strong) NSDictionary* pluginsMap;
-@property (nonatomic, readonly, strong) NSDictionary* settings;
+@property (nonatomic, readonly, strong) NSMutableDictionary* settings;
 @property (nonatomic, readonly, strong) NSXMLParser* configParser;
 @property (nonatomic, readonly, strong) CDVWhitelist* whitelist; // readonly for public
 @property (nonatomic, readonly, assign) BOOL loadFromString;
-
-@property (nonatomic, readwrite, assign) BOOL useSplashScreen;
-@property (nonatomic, readonly, strong) IBOutlet UIActivityIndicatorView* activityView;
-@property (nonatomic, readonly, strong) UIImageView* imageView;
+@property (nonatomic, readwrite, assign) BOOL useSplashScreen CDV_DEPRECATED(2.5, "Add/Remove the SplashScreen plugin instead of setting this property.");
 
 @property (nonatomic, readwrite, copy) NSString* wwwFolderName;
 @property (nonatomic, readwrite, copy) NSString* startPage;
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m b/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m
index 36ae785..bec716d 100644
--- a/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVViewController.m
@@ -23,23 +23,24 @@
 #import "CDVCommandDelegateImpl.h"
 #import "CDVConfigParser.h"
 #import "CDVUserAgentUtil.h"
+#import "CDVWebViewDelegate.h"
 
 #define degreesToRadian(x) (M_PI * (x) / 180.0)
 
 @interface CDVViewController () {
     NSInteger _userAgentLockToken;
+    CDVWebViewDelegate* _webViewDelegate;
 }
 
 @property (nonatomic, readwrite, strong) NSXMLParser* configParser;
-@property (nonatomic, readwrite, strong) NSDictionary* settings;
+@property (nonatomic, readwrite, strong) NSMutableDictionary* settings;
 @property (nonatomic, readwrite, strong) CDVWhitelist* whitelist;
 @property (nonatomic, readwrite, strong) NSMutableDictionary* pluginObjects;
+@property (nonatomic, readwrite, strong) NSArray* startupPluginNames;
 @property (nonatomic, readwrite, strong) NSDictionary* pluginsMap;
 @property (nonatomic, readwrite, strong) NSArray* supportedOrientations;
 @property (nonatomic, readwrite, assign) BOOL loadFromString;
 
-@property (nonatomic, readwrite, strong) IBOutlet UIActivityIndicatorView* activityView;
-@property (nonatomic, readwrite, strong) UIImageView* imageView;
 @property (readwrite, assign) BOOL initialized;
 
 @property (atomic, strong) NSURL* openURL;
@@ -49,9 +50,9 @@
 @implementation CDVViewController
 
 @synthesize webView, supportedOrientations;
-@synthesize pluginObjects, pluginsMap, whitelist;
+@synthesize pluginObjects, pluginsMap, whitelist, startupPluginNames;
 @synthesize configParser, settings, loadFromString;
-@synthesize imageView, activityView, useSplashScreen;
+@synthesize useSplashScreen;
 @synthesize wwwFolderName, startPage, initialized, openURL;
 @synthesize commandDelegate = _commandDelegate;
 @synthesize commandQueue = _commandQueue;
@@ -61,9 +62,6 @@
     if ((self != nil) && !self.initialized) {
         _commandQueue = [[CDVCommandQueue alloc] initWithViewController:self];
         _commandDelegate = [[CDVCommandDelegateImpl alloc] initWithViewController:self];
-        [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
-        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivedOrientationChange)
-                                                     name:UIDeviceOrientationDidChangeNotification object:nil];
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillTerminate:)
                                                      name:UIApplicationWillTerminateNotification object:nil];
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAppWillResignActive:)
@@ -87,6 +85,7 @@
 
         // load config.xml settings
         [self loadSettings];
+        useSplashScreen = YES;
     }
 }
 
@@ -162,16 +161,20 @@
     [configParser parse];
 
     // Get the plugin dictionary, whitelist and settings from the delegate.
-    self.pluginsMap = [delegate.pluginsDict dictionaryWithLowercaseKeys];
+    self.pluginsMap = delegate.pluginsDict;
+    self.startupPluginNames = delegate.startupPluginNames;
     self.whitelist = [[CDVWhitelist alloc] initWithArray:delegate.whitelistHosts];
     self.settings = delegate.settings;
 
     // And the start folder/page.
     self.wwwFolderName = @"www";
-    self.startPage = [delegate getStartPage];
+    self.startPage = delegate.startPage;
+    if (self.startPage == nil) {
+        self.startPage = @"index.html";
+    }
 
     // Initialize the plugin objects dict.
-    self.pluginObjects = [[NSMutableDictionary alloc] initWithCapacity:4];
+    self.pluginObjects = [[NSMutableDictionary alloc] initWithCapacity:20];
 }
 
 // Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
@@ -202,13 +205,14 @@
 
     NSString* backupWebStorageType = @"cloud"; // default value
 
-    id backupWebStorage = [self.settings objectForKey:@"BackupWebStorage"];
+    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;
 
     if (IsAtLeastiOSVersion(@"5.1")) {
         [CDVLocalStorage __fixupDatabaseLocationsWithBackupType:backupWebStorageType];
@@ -243,8 +247,7 @@
      */
     if (IsAtLeastiOSVersion(@"5.1") && (([backupWebStorageType isEqualToString:@"local"]) ||
             ([backupWebStorageType isEqualToString:@"cloud"] && !IsAtLeastiOSVersion(@"6.0")))) {
-        [self registerPlugin:[[CDVLocalStorage alloc] initWithWebView:self.webView settings:[NSDictionary dictionaryWithObjectsAndKeys:
-                    @"backupType", backupWebStorageType, nil]] withClassName:NSStringFromClass([CDVLocalStorage class])];
+        [self registerPlugin:[[CDVLocalStorage alloc] initWithWebView:self.webView] withClassName:NSStringFromClass([CDVLocalStorage class])];
     }
 
     /*
@@ -304,6 +307,15 @@
         }
     }
 
+    for (NSString* pluginName in self.startupPluginNames) {
+        [self getCommandInstance:pluginName];
+    }
+
+    // TODO: Remove this explicit instantiation once we move to cordova-CLI.
+    if (useSplashScreen) {
+        [self getCommandInstance:@"splashscreen"];
+    }
+
     // /////////////////
     [CDVUserAgentUtil acquireLock:^(NSInteger lockToken) {
             _userAgentLockToken = lockToken;
@@ -441,7 +453,8 @@
         [self.view addSubview:self.webView];
         [self.view sendSubviewToBack:self.webView];
 
-        self.webView.delegate = self;
+        _webViewDelegate = [[CDVWebViewDelegate alloc] initWithDelegate:self];
+        self.webView.delegate = _webViewDelegate;
 
         // register this viewcontroller with the NSURLProtocol, only after the User-Agent is set
         [CDVURLProtocol registerViewController:self];
@@ -480,6 +493,7 @@
 
     self.webView.delegate = nil;
     self.webView = nil;
+    [CDVUserAgentUtil releaseLock:&_userAgentLockToken];
 }
 
 #pragma mark UIWebViewDelegate
@@ -490,33 +504,19 @@
  */
 - (void)webViewDidStartLoad:(UIWebView*)theWebView
 {
+    NSLog(@"Resetting plugins due to page load.");
     [_commandQueue resetRequestId];
-    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginResetNotification object:nil]];
+    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginResetNotification object:self.webView]];
 }
 
 /**
- Called when the webview finishes loading.  This stops the activity view and closes the imageview
+ Called when the webview finishes loading.  This stops the activity view.
  */
 - (void)webViewDidFinishLoad:(UIWebView*)theWebView
 {
-    if (_userAgentLockToken != 0) {
-        [CDVUserAgentUtil releaseLock:_userAgentLockToken];
-        _userAgentLockToken = 0;
-    }
-
-    /*
-     * Hide the Top Activity THROBBER in the Battery Bar
-     */
-    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
-
-    id autoHideSplashScreenValue = [self.settings objectForKey:@"AutoHideSplashScreen"];
-    // if value is missing, default to yes
-    if ((autoHideSplashScreenValue == nil) || [autoHideSplashScreenValue boolValue]) {
-        self.imageView.hidden = YES;
-        self.activityView.hidden = YES;
-        [self.view.superview bringSubviewToFront:self.webView];
-    }
-    [self didRotateFromInterfaceOrientation:(UIInterfaceOrientation)[[UIDevice currentDevice] orientation]];
+    NSLog(@"Finished load of: %@", theWebView.request.URL);
+    // 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.
@@ -524,22 +524,21 @@
     // 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
+     */
+    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
+
     [self processOpenUrl];
+
+    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPageDidLoadNotification object:nil]];
 }
 
-- (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error
+- (void)webView:(UIWebView*)theWebView didFailLoadWithError:(NSError*)error
 {
-    if (_userAgentLockToken != 0) {
-        [CDVUserAgentUtil releaseLock:_userAgentLockToken];
-        _userAgentLockToken = 0;
-    }
+    [CDVUserAgentUtil releaseLock:&_userAgentLockToken];
 
     NSLog(@"Failed to load webpage with error: %@", [error localizedDescription]);
-
-    /*
-     if ([error code] != NSURLErrorCancelled)
-     alert([error localizedDescription]);
-     */
 }
 
 - (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
@@ -595,8 +594,6 @@
      * Handle all other types of urls (tel:, sms:), and requests to load a url in the main webview.
      */
     else {
-        // BOOL isIFrame = ([theWebView.request.mainDocumentURL absoluteString] == nil);
-
         if ([self.whitelist schemeIsAllowed:[url scheme]]) {
             return [self.whitelist URLIsAllowed:url];
         } else {
@@ -647,131 +644,6 @@
     return basePath;
 }
 
-- (void)showSplashScreen
-{
-    CGRect screenBounds = [[UIScreen mainScreen] bounds];
-    NSString* launchImageFile = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UILaunchImageFile"];
-
-    if (launchImageFile == nil) { // fallback if no launch image was specified
-        if (CDV_IsIPhone5()) {
-            // iPhone 5 or iPod Touch 6th-gen
-            launchImageFile = @"Default-568h";
-        } else {
-            launchImageFile = @"Default";
-        }
-    }
-
-    NSString* orientedLaunchImageFile = nil;
-    CGAffineTransform startupImageTransform = CGAffineTransformIdentity;
-    UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
-    CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
-    UIInterfaceOrientation statusBarOrientation = [UIApplication sharedApplication].statusBarOrientation;
-    UIImage* launchImage = nil;
-
-    // default to center of screen as in the original implementation. This will produce the 20px jump
-    CGPoint center = CGPointMake((screenBounds.size.width / 2), (screenBounds.size.height / 2));
-
-    if (CDV_IsIPad()) {
-        if (!UIDeviceOrientationIsValidInterfaceOrientation(deviceOrientation)) {
-            deviceOrientation = (UIDeviceOrientation)statusBarOrientation;
-        }
-
-        switch (deviceOrientation) {
-            case UIDeviceOrientationLandscapeLeft: // this is where the home button is on the right (yeah, I know, confusing)
-                {
-                    orientedLaunchImageFile = [NSString stringWithFormat:@"%@-Landscape", launchImageFile];
-                    startupImageTransform = CGAffineTransformMakeRotation(degreesToRadian(90));
-                    center.x -= MIN(statusBarFrame.size.width, statusBarFrame.size.height) / 2;
-                }
-                break;
-
-            case UIDeviceOrientationLandscapeRight: // this is where the home button is on the left (yeah, I know, confusing)
-                {
-                    orientedLaunchImageFile = [NSString stringWithFormat:@"%@-Landscape", launchImageFile];
-                    startupImageTransform = CGAffineTransformMakeRotation(degreesToRadian(-90));
-                    center.x += MIN(statusBarFrame.size.width, statusBarFrame.size.height) / 2;
-                }
-                break;
-
-            case UIDeviceOrientationPortraitUpsideDown:
-                {
-                    orientedLaunchImageFile = [NSString stringWithFormat:@"%@-Portrait", launchImageFile];
-                    startupImageTransform = CGAffineTransformMakeRotation(degreesToRadian(180));
-                    center.y -= MIN(statusBarFrame.size.width, statusBarFrame.size.height) / 2;
-                }
-                break;
-
-            case UIDeviceOrientationPortrait:
-            default:
-                {
-                    orientedLaunchImageFile = [NSString stringWithFormat:@"%@-Portrait", launchImageFile];
-                    startupImageTransform = CGAffineTransformIdentity;
-                    center.y += MIN(statusBarFrame.size.width, statusBarFrame.size.height) / 2;
-                }
-                break;
-        }
-    } else { // not iPad
-        orientedLaunchImageFile = launchImageFile;
-    }
-
-    launchImage = [UIImage imageNamed:[[self class] resolveImageResource:orientedLaunchImageFile]];
-    if (launchImage == nil) {
-        NSLog(@"WARNING: Splash-screen image '%@' was not found. Orientation: %d, iPad: %d", orientedLaunchImageFile, deviceOrientation, CDV_IsIPad());
-    }
-
-    self.imageView = [[UIImageView alloc] initWithImage:launchImage];
-    self.imageView.tag = 1;
-    self.imageView.center = center;
-
-    self.imageView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin);
-    [self.imageView setTransform:startupImageTransform];
-    [self.view.superview addSubview:self.imageView];
-
-    /*
-     * The Activity View is the top spinning throbber in the status/battery bar. We init it with the default Grey Style.
-     *
-     *     whiteLarge = UIActivityIndicatorViewStyleWhiteLarge
-     *     white      = UIActivityIndicatorViewStyleWhite
-     *     gray       = UIActivityIndicatorViewStyleGray
-     *
-     */
-    NSString* topActivityIndicator = [self.settings objectForKey:@"TopActivityIndicator"];
-    UIActivityIndicatorViewStyle topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray;
-
-    if ([topActivityIndicator isEqualToString:@"whiteLarge"]) {
-        topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhiteLarge;
-    } else if ([topActivityIndicator isEqualToString:@"white"]) {
-        topActivityIndicatorStyle = UIActivityIndicatorViewStyleWhite;
-    } else if ([topActivityIndicator isEqualToString:@"gray"]) {
-        topActivityIndicatorStyle = UIActivityIndicatorViewStyleGray;
-    }
-
-    self.activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:topActivityIndicatorStyle];
-    self.activityView.tag = 2;
-
-    id showSplashScreenSpinnerValue = [self.settings objectForKey:@"ShowSplashScreenSpinner"];
-    // backwards compatibility - if key is missing, default to true
-    if ((showSplashScreenSpinnerValue == nil) || [showSplashScreenSpinnerValue boolValue]) {
-        [self.view.superview addSubview:self.activityView];
-    }
-
-    self.activityView.center = self.view.center;
-    [self.activityView startAnimating];
-
-    [self.view.superview layoutSubviews];
-}
-
-BOOL gSplashScreenShown = NO;
-- (void)receivedOrientationChange
-{
-    if (self.imageView == nil) {
-        gSplashScreenShown = YES;
-        if (self.useSplashScreen) {
-            [self showSplashScreen];
-        }
-    }
-}
-
 #pragma mark CordovaCommands
 
 - (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className
@@ -785,6 +657,7 @@
     }
 
     [self.pluginObjects setObject:plugin forKey:className];
+    [plugin pluginInitialize];
 }
 
 /**
@@ -805,16 +678,9 @@
 
     id obj = [self.pluginObjects objectForKey:className];
     if (!obj) {
-        // attempt to load the settings for this command class
-        NSDictionary* classSettings = [self.settings objectForKey:className];
+        obj = [[NSClassFromString (className)alloc] initWithWebView:webView];
 
-        if (classSettings) {
-            obj = [[NSClassFromString (className)alloc] initWithWebView:webView settings:classSettings];
-        } else {
-            obj = [[NSClassFromString (className)alloc] initWithWebView:webView];
-        }
-
-        if ((obj != nil) && [obj isKindOfClass:[CDVPlugin class]]) {
+        if (obj != nil) {
             [self registerPlugin:obj withClassName:className];
         } else {
             NSLog(@"CDVPlugin class %@ (pluginName: %@) does not exist.", className, pluginName);
@@ -955,9 +821,9 @@
     [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSCurrentLocaleDidChangeNotification object:nil];
     [[NSNotificationCenter defaultCenter] removeObserver:self name:CDVPluginHandleOpenURLNotification object:nil];
-
     self.webView.delegate = nil;
     self.webView = nil;
+    [CDVUserAgentUtil releaseLock:&_userAgentLockToken];
     [_commandQueue dispose];
     [[self.pluginObjects allValues] makeObjectsPerformSelector:@selector(dispose)];
 }
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.h b/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.h
new file mode 100644
index 0000000..8a89a22
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.h
@@ -0,0 +1,37 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements.  See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership.  The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License.  You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied.  See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import <UIKit/UIKit.h>
+
+/**
+ * Distinguishes top-level navigations from sub-frame navigations.
+ * shouldStartLoadWithRequest is called for every request, but didStartLoad
+ * and didFinishLoad is called only for top-level navigations.
+ * Relevant bug: CB-2389
+ */
+@interface CDVWebViewDelegate : NSObject <UIWebViewDelegate>{
+    __weak NSObject <UIWebViewDelegate>* _delegate;
+    NSInteger _loadCount;
+    NSInteger _state;
+    NSInteger _curLoadToken;
+}
+
+- (id)initWithDelegate:(NSObject <UIWebViewDelegate>*)delegate;
+
+@end
diff --git a/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m b/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m
new file mode 100644
index 0000000..9ee8186
--- /dev/null
+++ b/lib/cordova-ios/CordovaLib/Classes/CDVWebViewDelegate.m
@@ -0,0 +1,157 @@
+/*
+ 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 "CDVWebViewDelegate.h"
+#import "CDVAvailability.h"
+
+typedef enum {
+    STATE_NORMAL,
+    STATE_SHOULD_LOAD_MISSING,
+    STATE_WAITING_FOR_START,
+    STATE_WAITING_FOR_FINISH
+} State;
+
+@implementation CDVWebViewDelegate
+
+- (id)initWithDelegate:(NSObject <UIWebViewDelegate>*)delegate
+{
+    self = [super init];
+    if (self != nil) {
+        _delegate = delegate;
+        _loadCount = -1;
+        _state = STATE_NORMAL;
+    }
+    return self;
+}
+
+- (BOOL)isPageLoaded:(UIWebView*)webView
+{
+    NSString* readyState = [webView stringByEvaluatingJavaScriptFromString:@"document.readyState"];
+
+    return [readyState isEqualToString:@"loaded"] || [readyState isEqualToString:@"complete"];
+}
+
+- (BOOL)isJsLoadTokenSet:(UIWebView*)webView
+{
+    NSString* loadToken = [webView stringByEvaluatingJavaScriptFromString:@"window.__cordovaLoadToken"];
+
+    return [[NSString stringWithFormat:@"%d", _curLoadToken] isEqualToString:loadToken];
+}
+
+- (void)setLoadToken:(UIWebView*)webView
+{
+    _curLoadToken += 1;
+    [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"window.__cordovaLoadToken=%d", _curLoadToken]];
+}
+
+- (void)pollForPageLoadStart:(UIWebView*)webView
+{
+    if ((_state != STATE_WAITING_FOR_START) && (_state != STATE_SHOULD_LOAD_MISSING)) {
+        return;
+    }
+    if (![self isJsLoadTokenSet:webView]) {
+        _state = STATE_WAITING_FOR_FINISH;
+        [self setLoadToken:webView];
+        [_delegate webViewDidStartLoad:webView];
+        [self pollForPageLoadFinish:webView];
+    }
+}
+
+- (void)pollForPageLoadFinish:(UIWebView*)webView
+{
+    if (_state != STATE_WAITING_FOR_FINISH) {
+        return;
+    }
+    if ([self isPageLoaded:webView]) {
+        _state = STATE_SHOULD_LOAD_MISSING;
+        [_delegate webViewDidFinishLoad:webView];
+    } else {
+        [self performSelector:@selector(pollForPageLoaded) withObject:webView afterDelay:50];
+    }
+}
+
+- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
+{
+    BOOL shouldLoad = [_delegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType];
+
+    if (shouldLoad) {
+        BOOL isTopLevelNavigation = [request.URL isEqual:[request mainDocumentURL]];
+        if (isTopLevelNavigation) {
+            _loadCount = 0;
+            _state = STATE_NORMAL;
+        }
+    }
+    return shouldLoad;
+}
+
+- (void)webViewDidStartLoad:(UIWebView*)webView
+{
+    if (_state == STATE_NORMAL) {
+        if (_loadCount == 0) {
+            [_delegate webViewDidStartLoad:webView];
+            _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;
+            [self setLoadToken:webView];
+        }
+    } else {
+        [self pollForPageLoadStart:webView];
+        [self pollForPageLoadFinish:webView];
+    }
+}
+
+- (void)webViewDidFinishLoad:(UIWebView*)webView
+{
+    if (_state == STATE_NORMAL) {
+        if (_loadCount == 1) {
+            [_delegate webViewDidFinishLoad:webView];
+            _loadCount -= 1;
+        } else if (_loadCount > 1) {
+            _loadCount -= 1;
+        }
+    } else {
+        [self pollForPageLoadStart:webView];
+        [self pollForPageLoadFinish:webView];
+    }
+}
+
+- (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error
+{
+    if (_state == STATE_NORMAL) {
+        if (_loadCount == 1) {
+            [_delegate webView:webView didFailLoadWithError:error];
+            _loadCount -= 1;
+        } else if (_loadCount > 1) {
+            _loadCount -= 1;
+        }
+    } else {
+        [self pollForPageLoadStart:webView];
+        [self pollForPageLoadFinish:webView];
+    }
+}
+
+@end
diff --git a/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj b/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
index 53d2d23..4868020 100644
--- a/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
+++ b/lib/cordova-ios/CordovaLib/CordovaLib.xcodeproj/project.pbxproj
@@ -84,6 +84,8 @@
 		EB96673C16A8970A00D86CDF /* CDVUserAgentUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = EB96673A16A8970900D86CDF /* CDVUserAgentUtil.m */; };
 		EBA3557315ABD38C00F4DE24 /* NSArray+Comparisons.h in Headers */ = {isa = PBXBuildFile; fileRef = EBA3557115ABD38C00F4DE24 /* NSArray+Comparisons.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		EBA3557515ABD38C00F4DE24 /* NSArray+Comparisons.m in Sources */ = {isa = PBXBuildFile; fileRef = EBA3557215ABD38C00F4DE24 /* NSArray+Comparisons.m */; };
+		EBFF4DBC16D3FE2E008F452B /* CDVWebViewDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = EBFF4DBA16D3FE2E008F452B /* CDVWebViewDelegate.m */; };
+		EBFF4DBD16D3FE2E008F452B /* CDVWebViewDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = EBFF4DBB16D3FE2E008F452B /* CDVWebViewDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		F858FBC6166009A8007DA594 /* CDVConfigParser.h in Headers */ = {isa = PBXBuildFile; fileRef = F858FBC4166009A8007DA594 /* CDVConfigParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		F858FBC7166009A8007DA594 /* CDVConfigParser.m in Sources */ = {isa = PBXBuildFile; fileRef = F858FBC5166009A8007DA594 /* CDVConfigParser.m */; };
 /* End PBXBuildFile section */
@@ -180,6 +182,8 @@
 		EB96673A16A8970900D86CDF /* CDVUserAgentUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVUserAgentUtil.m; path = Classes/CDVUserAgentUtil.m; sourceTree = "<group>"; };
 		EBA3557115ABD38C00F4DE24 /* NSArray+Comparisons.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSArray+Comparisons.h"; path = "Classes/NSArray+Comparisons.h"; sourceTree = "<group>"; };
 		EBA3557215ABD38C00F4DE24 /* NSArray+Comparisons.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSArray+Comparisons.m"; path = "Classes/NSArray+Comparisons.m"; sourceTree = "<group>"; };
+		EBFF4DBA16D3FE2E008F452B /* CDVWebViewDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVWebViewDelegate.m; path = Classes/CDVWebViewDelegate.m; sourceTree = "<group>"; };
+		EBFF4DBB16D3FE2E008F452B /* CDVWebViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVWebViewDelegate.h; path = Classes/CDVWebViewDelegate.h; sourceTree = "<group>"; };
 		F858FBC4166009A8007DA594 /* CDVConfigParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVConfigParser.h; path = Classes/CDVConfigParser.h; sourceTree = "<group>"; };
 		F858FBC5166009A8007DA594 /* CDVConfigParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVConfigParser.m; path = Classes/CDVConfigParser.m; sourceTree = "<group>"; };
 /* End PBXFileReference section */
@@ -257,6 +261,8 @@
 		888700D710922F56009987E8 /* Commands */ = {
 			isa = PBXGroup;
 			children = (
+				EBFF4DBA16D3FE2E008F452B /* CDVWebViewDelegate.m */,
+				EBFF4DBB16D3FE2E008F452B /* CDVWebViewDelegate.h */,
 				30C5F1DD15AF9E950052A00D /* CDVDevice.h */,
 				30C5F1DE15AF9E950052A00D /* CDVDevice.m */,
 				301F2F2914F3C9CA003FE9FC /* CDV.h */,
@@ -399,6 +405,7 @@
 				3073E9ED1656D51200957977 /* CDVScreenOrientationDelegate.h in Headers */,
 				F858FBC6166009A8007DA594 /* CDVConfigParser.h in Headers */,
 				30F3930B169F839700B22307 /* CDVJSON.h in Headers */,
+				EBFF4DBD16D3FE2E008F452B /* CDVWebViewDelegate.h in Headers */,
 				EB96673B16A8970A00D86CDF /* CDVUserAgentUtil.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -429,7 +436,7 @@
 		0867D690FE84028FC02AAC07 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 0430;
+				LastUpgradeCheck = 0460;
 			};
 			buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "CordovaLib" */;
 			compatibilityVersion = "Xcode 3.2";
@@ -494,6 +501,7 @@
 				F858FBC7166009A8007DA594 /* CDVConfigParser.m in Sources */,
 				30F3930C169F839700B22307 /* CDVJSON.m in Sources */,
 				EB96673C16A8970A00D86CDF /* CDVUserAgentUtil.m in Sources */,
+				EBFF4DBC16D3FE2E008F452B /* CDVWebViewDelegate.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -564,12 +572,17 @@
 					armv7s,
 				);
 				"ARCHS[sdk=iphonesimulator*]" = i386;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				GCC_C_LANGUAGE_STANDARD = c99;
 				GCC_OPTIMIZATION_LEVEL = 0;
 				GCC_PREPROCESSOR_DEFINITIONS = "";
 				GCC_THUMB_SUPPORT = NO;
 				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				IPHONEOS_DEPLOYMENT_TARGET = 4.3;
 				ONLY_ACTIVE_ARCH = NO;
@@ -592,11 +605,16 @@
 					armv7s,
 				);
 				"ARCHS[sdk=iphonesimulator*]" = i386;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				GCC_C_LANGUAGE_STANDARD = c99;
 				GCC_PREPROCESSOR_DEFINITIONS = "";
 				GCC_THUMB_SUPPORT = NO;
 				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				IPHONEOS_DEPLOYMENT_TARGET = 4.3;
 				ONLY_ACTIVE_ARCH = NO;
diff --git a/lib/cordova-ios/CordovaLib/VERSION b/lib/cordova-ios/CordovaLib/VERSION
index 197c4d5..aa0822f 100644
--- a/lib/cordova-ios/CordovaLib/VERSION
+++ b/lib/cordova-ios/CordovaLib/VERSION
@@ -1 +1 @@
-2.4.0
+2.5.0rc1
diff --git a/lib/cordova-ios/CordovaLib/cordova.ios.js b/lib/cordova-ios/CordovaLib/cordova.ios.js
index bc15819..60665b6 100644
--- a/lib/cordova-ios/CordovaLib/cordova.ios.js
+++ b/lib/cordova-ios/CordovaLib/cordova.ios.js
@@ -1,8 +1,8 @@
 // Platform: ios
 
-// commit ac725f6ae0bd655789771e2a40b8d60cb4c8c221
+// commit 521bbd64ed729ca76b6646d25bb01b76ee8a54b5
 
-// File generated at :: Tue Feb 05 2013 05:30:42 GMT+0100 (CET)
+// File generated at :: Wed Feb 20 2013 12:24:41 GMT-0800 (PST)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -399,6 +399,7 @@
 }
 
 function clobber(obj, key, value) {
+    exports.replaceHookForTesting(obj, key);
     obj[key] = value;
     // Getters can only be overridden by getters.
     if (obj[key] !== value) {
@@ -482,19 +483,18 @@
     }
 }
 
-module.exports = {
-    buildIntoButDoNotClobber: function(objects, target) {
-        include(target, objects, false, false);
-    },
-    buildIntoAndClobber: function(objects, target) {
-        include(target, objects, true, false);
-    },
-    buildIntoAndMerge: function(objects, target) {
-        include(target, objects, true, true);
-    },
-    recursiveMerge: recursiveMerge,
-    assignOrWrapInDeprecateGetter: assignOrWrapInDeprecateGetter
+exports.buildIntoButDoNotClobber = function(objects, target) {
+    include(target, objects, false, false);
 };
+exports.buildIntoAndClobber = function(objects, target) {
+    include(target, objects, true, false);
+};
+exports.buildIntoAndMerge = function(objects, target) {
+    include(target, objects, true, true);
+};
+exports.recursiveMerge = recursiveMerge;
+exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
+exports.replaceHookForTesting = function() {};
 
 });
 
@@ -774,176 +774,6 @@
 };
 });
 
-// file: lib/common/common.js
-define("cordova/common", function(require, exports, module) {
-
-module.exports = {
-    defaults: {
-        cordova: {
-            path: 'cordova',
-            children: {
-                exec: {
-                    path: 'cordova/exec'
-                },
-                logger: {
-                    path: 'cordova/plugin/logger'
-                }
-            }
-        },
-        Cordova: {
-            children: {
-                exec: {
-                    path: 'cordova/exec'
-                }
-            }
-        },
-        open : {
-            path: 'cordova/plugin/InAppBrowser'
-        },
-        navigator: {
-            children: {
-                notification: {
-                    path: 'cordova/plugin/notification'
-                },
-                accelerometer: {
-                    path: 'cordova/plugin/accelerometer'
-                },
-                battery: {
-                    path: 'cordova/plugin/battery'
-                },
-                camera:{
-                    path: 'cordova/plugin/Camera'
-                },
-                compass:{
-                    path: 'cordova/plugin/compass'
-                },
-                contacts: {
-                    path: 'cordova/plugin/contacts'
-                },
-                device:{
-                    children:{
-                        capture: {
-                            path: 'cordova/plugin/capture'
-                        }
-                    }
-                },
-                geolocation: {
-                    path: 'cordova/plugin/geolocation'
-                },
-                globalization: {
-                    path: 'cordova/plugin/globalization'
-                },
-                network: {
-                    children: {
-                        connection: {
-                            path: 'cordova/plugin/network',
-                            deprecated: 'navigator.network.connection is deprecated. Use navigator.connection instead.'
-                        }
-                    }
-                },
-                splashscreen: {
-                    path: 'cordova/plugin/splashscreen'
-                }
-            }
-        },
-        Acceleration: {
-            path: 'cordova/plugin/Acceleration'
-        },
-        Camera:{
-            path: 'cordova/plugin/CameraConstants'
-        },
-        CameraPopoverOptions: {
-            path: 'cordova/plugin/CameraPopoverOptions'
-        },
-        CaptureError: {
-            path: 'cordova/plugin/CaptureError'
-        },
-        CaptureAudioOptions:{
-            path: 'cordova/plugin/CaptureAudioOptions'
-        },
-        CaptureImageOptions: {
-            path: 'cordova/plugin/CaptureImageOptions'
-        },
-        CaptureVideoOptions: {
-            path: 'cordova/plugin/CaptureVideoOptions'
-        },
-        CompassHeading:{
-            path: 'cordova/plugin/CompassHeading'
-        },
-        CompassError:{
-            path: 'cordova/plugin/CompassError'
-        },
-        ConfigurationData: {
-            path: 'cordova/plugin/ConfigurationData'
-        },
-        Connection: {
-            path: 'cordova/plugin/Connection'
-        },
-        Contact: {
-            path: 'cordova/plugin/Contact'
-        },
-        ContactAddress: {
-            path: 'cordova/plugin/ContactAddress'
-        },
-        ContactError: {
-            path: 'cordova/plugin/ContactError'
-        },
-        ContactField: {
-            path: 'cordova/plugin/ContactField'
-        },
-        ContactFindOptions: {
-            path: 'cordova/plugin/ContactFindOptions'
-        },
-        ContactName: {
-            path: 'cordova/plugin/ContactName'
-        },
-        ContactOrganization: {
-            path: 'cordova/plugin/ContactOrganization'
-        },
-        Coordinates: {
-            path: 'cordova/plugin/Coordinates'
-        },
-        device: {
-            path: 'cordova/plugin/device'
-        },
-        GlobalizationError: {
-            path: 'cordova/plugin/GlobalizationError'
-        },
-        Media: {
-            path: 'cordova/plugin/Media'
-        },
-        MediaError: {
-            path: 'cordova/plugin/MediaError'
-        },
-        MediaFile: {
-            path: 'cordova/plugin/MediaFile'
-        },
-        MediaFileData:{
-            path: 'cordova/plugin/MediaFileData'
-        },
-        Position: {
-            path: 'cordova/plugin/Position'
-        },
-        PositionError: {
-            path: 'cordova/plugin/PositionError'
-        },
-        ProgressEvent: {
-            path: 'cordova/plugin/ProgressEvent'
-        }
-    },
-    clobbers: {
-        navigator: {
-            children: {
-                connection: {
-                    path: 'cordova/plugin/network'
-                }
-            }
-        }
-    }
-};
-
-});
-
 // file: lib/ios/exec.js
 define("cordova/exec", function(require, exports, module) {
 
@@ -1197,9 +1027,9 @@
     var parts = symbolPath.split('.');
     var cur = context;
     for (var i = 0, part; part = parts[i]; ++i) {
-        cur[part] = cur[part] || {};
+        cur = cur[part] = cur[part] || {};
     }
-    return cur[parts[i-1]];
+    return cur;
 }
 
 exports.mapModules = function(context) {
@@ -1221,7 +1051,7 @@
         if (strategy == 'm' && target) {
             builder.recursiveMerge(target, module);
         } else if ((strategy == 'd' && !target) || (strategy != 'd')) {
-            if (target) {
+            if (!(symbolPath in origSymbols)) {
                 origSymbols[symbolPath] = target;
             }
             builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
@@ -1263,43 +1093,13 @@
     initialize:function() {
         var modulemapper = require('cordova/modulemapper');
 
+        modulemapper.loadMatchingModules(/cordova.*\/plugininit$/);
+
         modulemapper.loadMatchingModules(/cordova.*\/symbols$/);
         modulemapper.mapModules(window);
-    },
-    clobbers: {
-        MediaError: { // exists natively, override
-            path: "cordova/plugin/MediaError"
-        },
-        console: {
-            path: 'cordova/plugin/ios/console'
-        },
-        open : {
-            path: 'cordova/plugin/InAppBrowser'
-        }
-    },
-    merges:{
-        Contact:{
-            path: "cordova/plugin/ios/Contact"
-        },
-        navigator:{
-            children:{
-                notification:{
-                    path:"cordova/plugin/ios/notification"
-                },
-                contacts:{
-                    path:"cordova/plugin/ios/contacts"
-                },
-                geolocation: {
-                    path: 'cordova/plugin/geolocation'
-                }
-            }
-        }
     }
 };
 
-// use the native logger
-var logger = require("cordova/plugin/logger");
-logger.useConsole(false);
 
 });
 
@@ -1531,9 +1331,9 @@
 define("cordova/plugin/CompassHeading", function(require, exports, module) {
 
 var CompassHeading = function(magneticHeading, trueHeading, headingAccuracy, timestamp) {
-  this.magneticHeading = magneticHeading || null;
-  this.trueHeading = trueHeading || null;
-  this.headingAccuracy = headingAccuracy || null;
+  this.magneticHeading = magneticHeading;
+  this.trueHeading = trueHeading;
+  this.headingAccuracy = headingAccuracy;
   this.timestamp = timestamp || new Date().getTime();
 };
 
@@ -2906,11 +2706,12 @@
  * FileTransferError
  * @constructor
  */
-var FileTransferError = function(code, source, target, status) {
+var FileTransferError = function(code, source, target, status, body) {
     this.code = code || null;
     this.source = source || null;
     this.target = target || null;
     this.http_status = status || null;
+    this.body = body || null;
 };
 
 FileTransferError.FILE_NOT_FOUND_ERR = 1;
@@ -3314,8 +3115,6 @@
     return iab;
 };
 
-//Export the original open so it can be used if needed
-module.exports._orig = window.open;
 
 });
 
@@ -3886,6 +3685,17 @@
 
 });
 
+// file: lib/common/plugin/accelerometer/symbols.js
+define("cordova/plugin/accelerometer/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Acceleration', 'Acceleration');
+modulemapper.defaults('cordova/plugin/accelerometer', 'navigator.accelerometer');
+
+});
+
 // file: lib/common/plugin/battery.js
 define("cordova/plugin/battery", function(require, exports, module) {
 
@@ -3970,6 +3780,28 @@
 
 });
 
+// file: lib/common/plugin/battery/symbols.js
+define("cordova/plugin/battery/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/battery', 'navigator.battery');
+
+});
+
+// file: lib/common/plugin/camera/symbols.js
+define("cordova/plugin/camera/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Camera', 'navigator.camera');
+modulemapper.defaults('cordova/plugin/CameraConstants', 'Camera');
+modulemapper.defaults('cordova/plugin/CameraPopoverOptions', 'CameraPopoverOptions');
+
+});
+
 // file: lib/common/plugin/capture.js
 define("cordova/plugin/capture", function(require, exports, module) {
 
@@ -4048,6 +3880,22 @@
 
 });
 
+// file: lib/common/plugin/capture/symbols.js
+define("cordova/plugin/capture/symbols", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/CaptureError', 'CaptureError');
+modulemapper.clobbers('cordova/plugin/CaptureAudioOptions', 'CaptureAudioOptions');
+modulemapper.clobbers('cordova/plugin/CaptureImageOptions', 'CaptureImageOptions');
+modulemapper.clobbers('cordova/plugin/CaptureVideoOptions', 'CaptureVideoOptions');
+modulemapper.clobbers('cordova/plugin/ConfigurationData', 'ConfigurationData');
+modulemapper.clobbers('cordova/plugin/MediaFile', 'MediaFile');
+modulemapper.clobbers('cordova/plugin/MediaFileData', 'MediaFileData');
+modulemapper.clobbers('cordova/plugin/capture', 'navigator.device.capture');
+
+});
+
 // file: lib/common/plugin/compass.js
 define("cordova/plugin/compass", function(require, exports, module) {
 
@@ -4135,6 +3983,18 @@
 
 });
 
+// file: lib/common/plugin/compass/symbols.js
+define("cordova/plugin/compass/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/CompassHeading', 'CompassHeading');
+modulemapper.clobbers('cordova/plugin/CompassError', 'CompassError');
+modulemapper.clobbers('cordova/plugin/compass', 'navigator.compass');
+
+});
+
 // file: lib/common/plugin/console-via-logger.js
 define("cordova/plugin/console-via-logger", function(require, exports, module) {
 
@@ -4368,6 +4228,23 @@
 
 });
 
+// file: lib/common/plugin/contacts/symbols.js
+define("cordova/plugin/contacts/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/contacts', 'navigator.contacts');
+modulemapper.clobbers('cordova/plugin/Contact', 'Contact');
+modulemapper.clobbers('cordova/plugin/ContactAddress', 'ContactAddress');
+modulemapper.clobbers('cordova/plugin/ContactError', 'ContactError');
+modulemapper.clobbers('cordova/plugin/ContactField', 'ContactField');
+modulemapper.clobbers('cordova/plugin/ContactFindOptions', 'ContactFindOptions');
+modulemapper.clobbers('cordova/plugin/ContactName', 'ContactName');
+modulemapper.clobbers('cordova/plugin/ContactOrganization', 'ContactOrganization');
+
+});
+
 // file: lib/common/plugin/device.js
 define("cordova/plugin/device", function(require, exports, module) {
 
@@ -4427,6 +4304,16 @@
 
 });
 
+// file: lib/common/plugin/device/symbols.js
+define("cordova/plugin/device/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/device', 'device');
+
+});
+
 // file: lib/common/plugin/echo.js
 define("cordova/plugin/echo", function(require, exports, module) {
 
@@ -4474,20 +4361,30 @@
     exportFunc('cordova/plugin/FileError', 'FileError');
     exportFunc('cordova/plugin/FileReader', 'FileReader');
     exportFunc('cordova/plugin/FileSystem', 'FileSystem');
-    exportFunc('cordova/plugin/FileTransfer', 'FileTransfer');
-    exportFunc('cordova/plugin/FileTransferError', 'FileTransferError');
     exportFunc('cordova/plugin/FileUploadOptions', 'FileUploadOptions');
     exportFunc('cordova/plugin/FileUploadResult', 'FileUploadResult');
     exportFunc('cordova/plugin/FileWriter', 'FileWriter');
     exportFunc('cordova/plugin/Flags', 'Flags');
     exportFunc('cordova/plugin/LocalFileSystem', 'LocalFileSystem');
     exportFunc('cordova/plugin/Metadata', 'Metadata');
+    exportFunc('cordova/plugin/ProgressEvent', 'ProgressEvent');
     exportFunc('cordova/plugin/requestFileSystem', 'requestFileSystem');
     exportFunc('cordova/plugin/resolveLocalFileSystemURI', 'resolveLocalFileSystemURI');
 };
 
 });
 
+// file: lib/common/plugin/filetransfer/symbols.js
+define("cordova/plugin/filetransfer/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/FileTransfer', 'FileTransfer');
+modulemapper.clobbers('cordova/plugin/FileTransferError', 'FileTransferError');
+
+});
+
 // file: lib/common/plugin/geolocation.js
 define("cordova/plugin/geolocation", function(require, exports, module) {
 
@@ -4684,6 +4581,19 @@
 
 });
 
+// file: lib/common/plugin/geolocation/symbols.js
+define("cordova/plugin/geolocation/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/geolocation', 'navigator.geolocation');
+modulemapper.clobbers('cordova/plugin/PositionError', 'PositionError');
+modulemapper.clobbers('cordova/plugin/Position', 'Position');
+modulemapper.clobbers('cordova/plugin/Coordinates', 'Coordinates');
+
+});
+
 // file: lib/common/plugin/globalization.js
 define("cordova/plugin/globalization", function(require, exports, module) {
 
@@ -5060,6 +4970,27 @@
 
 });
 
+// file: lib/common/plugin/globalization/symbols.js
+define("cordova/plugin/globalization/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/globalization', 'navigator.globalization');
+modulemapper.clobbers('cordova/plugin/GlobalizationError', 'GlobalizationError');
+
+});
+
+// file: lib/ios/plugin/inappbrowser/symbols.js
+define("cordova/plugin/inappbrowser/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/InAppBrowser', 'open');
+
+});
+
 // file: lib/ios/plugin/ios/Contact.js
 define("cordova/plugin/ios/Contact", function(require, exports, module) {
 
@@ -5181,6 +5112,15 @@
 
 });
 
+// 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) {
 
@@ -5228,6 +5168,36 @@
 
 });
 
+// file: lib/ios/plugin/ios/contacts/symbols.js
+define("cordova/plugin/ios/contacts/symbols", function(require, exports, module) {
+
+require('cordova/plugin/contacts/symbols');
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.merges('cordova/plugin/ios/contacts', 'navigator.contacts');
+modulemapper.merges('cordova/plugin/ios/Contact', 'Contact');
+
+});
+
+// file: lib/ios/plugin/ios/geolocation/symbols.js
+define("cordova/plugin/ios/geolocation/symbols", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.merges('cordova/plugin/geolocation', 'navigator.geolocation');
+
+});
+
+// file: lib/ios/plugin/ios/logger/plugininit.js
+define("cordova/plugin/ios/logger/plugininit", function(require, exports, module) {
+
+// use the native logger
+var logger = require("cordova/plugin/logger");
+logger.useConsole(false);
+
+});
+
 // file: lib/ios/plugin/ios/notification.js
 define("cordova/plugin/ios/notification", function(require, exports, module) {
 
@@ -5469,6 +5439,27 @@
 
 });
 
+// file: lib/common/plugin/logger/symbols.js
+define("cordova/plugin/logger/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/logger', 'cordova.logger');
+
+});
+
+// file: lib/ios/plugin/media/symbols.js
+define("cordova/plugin/media/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.defaults('cordova/plugin/Media', 'Media');
+modulemapper.clobbers('cordova/plugin/MediaError', 'MediaError');
+
+});
+
 // file: lib/common/plugin/network.js
 define("cordova/plugin/network", function(require, exports, module) {
 
@@ -5541,6 +5532,18 @@
 
 });
 
+// file: lib/common/plugin/networkstatus/symbols.js
+define("cordova/plugin/networkstatus/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/network', 'navigator.network.connection', 'navigator.network.connection is deprecated. Use navigator.connection instead.');
+modulemapper.clobbers('cordova/plugin/network', 'navigator.connection');
+modulemapper.defaults('cordova/plugin/Connection', 'Connection');
+
+});
+
 // file: lib/common/plugin/notification.js
 define("cordova/plugin/notification", function(require, exports, module) {
 
@@ -5603,6 +5606,17 @@
 
 });
 
+// file: lib/ios/plugin/notification/symbols.js
+define("cordova/plugin/notification/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/notification', 'navigator.notification');
+modulemapper.merges('cordova/plugin/ios/notification', 'navigator.notification');
+
+});
+
 // file: lib/common/plugin/requestFileSystem.js
 define("cordova/plugin/requestFileSystem", function(require, exports, module) {
 
@@ -5716,6 +5730,29 @@
 
 });
 
+// file: lib/common/plugin/splashscreen/symbols.js
+define("cordova/plugin/splashscreen/symbols", function(require, exports, module) {
+
+
+var modulemapper = require('cordova/modulemapper');
+
+modulemapper.clobbers('cordova/plugin/splashscreen', 'navigator.splashscreen');
+
+});
+
+// file: lib/common/symbols.js
+define("cordova/symbols", function(require, exports, module) {
+
+var modulemapper = require('cordova/modulemapper');
+
+// Use merges here in case others symbols files depend on this running first,
+// but fail to declare the dependency with a require().
+modulemapper.merges('cordova', 'cordova');
+modulemapper.clobbers('cordova/exec', 'cordova.exec');
+modulemapper.clobbers('cordova/exec', 'Cordova.exec');
+
+});
+
 // file: lib/common/utils.js
 define("cordova/utils", function(require, exports, module) {
 
@@ -5984,14 +6021,8 @@
                  */
                 channel.join(function() {
                     var builder = require('cordova/builder'),
-                        base = require('cordova/common'),
                         platform = require('cordova/platform');
 
-                    // Drop the common globals into the window object, but be nice and don't overwrite anything.
-                    builder.buildIntoButDoNotClobber(base.defaults, context);
-                    builder.buildIntoAndClobber(base.clobbers, context);
-                    builder.buildIntoAndMerge(base.merges, context);
-
                     builder.buildIntoButDoNotClobber(platform.defaults, context);
                     builder.buildIntoAndClobber(platform.clobbers, context);
                     builder.buildIntoAndMerge(platform.merges, context);
diff --git a/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml b/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml
index 9c36914..512bd1f 100644
--- a/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml
+++ b/lib/cordova-ios/CordovaLibTests/CordovaLibApp/config.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<cordova>
+<widget>
     <preference name="KeyboardDisplayRequiresUserAction" value="true" />
     <preference name="SuppressesIncrementalRendering" value="false" />
     <preference name="UIWebViewBounce" value="true" />
@@ -8,6 +8,8 @@
     <preference name="EnableViewportScale" value="false" />
     <preference name="AutoHideSplashScreen" value="true" />
     <preference name="ShowSplashScreenSpinner" value="true" />
+    <preference name="FadeSplashScreen" value="true" />
+    <preference name="FadeSplashScreenDuration" value="2" />
     <preference name="MediaPlaybackRequiresUserAction" value="false" />
     <preference name="AllowInlineMediaPlayback" value="false" />
     <preference name="BackupWebStorage" value="cloud" />
@@ -34,4 +36,4 @@
         <plugin name="Globalization" value="CDVGlobalization" />
         <plugin name="InAppBrowser" value="CDVInAppBrowser" />
     </plugins>
-</cordova>
+</widget>
diff --git a/lib/cordova-ios/bin/create b/lib/cordova-ios/bin/create
index b53c8a2..bef0f57 100755
--- a/lib/cordova-ios/bin/create
+++ b/lib/cordova-ios/bin/create
@@ -8,9 +8,9 @@
 # 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
@@ -21,7 +21,7 @@
 
 #
 # create a Cordova/iOS project
-# 
+#
 # USAGE
 #   ./create <path_to_new_project> <package_name> <project_name>
 #
@@ -79,7 +79,7 @@
 # Copy in the JS.
 cp "$CORDOVALIB_DIR/cordova.ios.js" "$PROJECT_PATH/www/cordova-$CDV_VER.js"
 # Change the filename reference in the html from cordova.ios.js -> cordova-VERSION.js.
-sed -i "" "s/src[ 	]*=[ 	]*[\\'\"]cordova.ios.js[\\'\"]/src=\"cordova-${CDV_VER}.js\"/g" "$PROJECT_PATH/www/index.html"
+/usr/bin/sed -i "" "s/src[ 	]*=[ 	]*[\\'\"]cordova.ios.js[\\'\"]/src=\"cordova-${CDV_VER}.js\"/g" "$PROJECT_PATH/www/index.html"
 
 # I've tried to be thorough in my documentation of the manual actions below...
 # on first brush it would seem that the right solution would be to brute force
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 67eb014..1d9c170 100755
--- a/lib/cordova-ios/bin/templates/project/__TESTING__.xcodeproj/project.pbxproj
+++ b/lib/cordova-ios/bin/templates/project/__TESTING__.xcodeproj/project.pbxproj
@@ -1,22 +1,4 @@
 // !$*UTF8*$!
-/*
- 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.
-*/
 {
 	archiveVersion = 1;
 	classes = {
@@ -33,7 +15,6 @@
 		1F766FE213BBADB100FB74C0 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1F766FDF13BBADB100FB74C0 /* Localizable.strings */; };
 		288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765FC0DF74451002DB57D /* CoreGraphics.framework */; };
 		301BF552109A68D80062928A /* libCordova.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF535109A57CC0062928A /* libCordova.a */; };
-		301BF570109A69640062928A /* www in Resources */ = {isa = PBXBuildFile; fileRef = 301BF56E109A69640062928A /* www */; };
 		301BF5B5109A6A2B0062928A /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF5B4109A6A2B0062928A /* AddressBook.framework */; };
 		301BF5B7109A6A2B0062928A /* AddressBookUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF5B6109A6A2B0062928A /* AddressBookUI.framework */; };
 		301BF5B9109A6A2B0062928A /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF5B8109A6A2B0062928A /* AudioToolbox.framework */; };
@@ -59,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, ); }; };
+		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 */; };
 /* End PBXBuildFile section */
@@ -119,6 +101,7 @@
 		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; };
 		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>"; };
 		D4A0D8751607E02300AEF8BB /* Default-568h@2x~iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x~iphone.png"; sourceTree = "<group>"; };
 		F840E1F0165FE0F500CFE078 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = config.xml; path = __TESTING__/config.xml; sourceTree = "<group>"; };
@@ -129,6 +112,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				5B1594DD16A7569C00FEF299 /* AssetsLibrary.framework in Frameworks */,
 				301BF552109A68D80062928A /* libCordova.a in Frameworks */,
 				1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */,
 				1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */,
@@ -232,6 +216,7 @@
 		29B97323FDCFA39411CA2CEA /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				5B1594DC16A7569C00FEF299 /* AssetsLibrary.framework */,
 				1DF5F4DF0D08C38300B7A737 /* UIKit.framework */,
 				1D30AB110D05D00D00671497 /* Foundation.framework */,
 				288765FC0DF74451002DB57D /* CoreGraphics.framework */,
@@ -313,7 +298,7 @@
 			isa = PBXNativeTarget;
 			buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "__TESTING__" */;
 			buildPhases = (
-				304B58A110DAC018002A0835 /* Touch www folder */,
+				304B58A110DAC018002A0835 /* Copy www directory */,
 				1D60588D0D05DD3D006BFB54 /* Resources */,
 				1D60588E0D05DD3D006BFB54 /* Sources */,
 				1D60588F0D05DD3D006BFB54 /* Frameworks */,
@@ -334,7 +319,7 @@
 		29B97313FDCFA39411CA2CEA /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastUpgradeCheck = 0430;
+				LastUpgradeCheck = 0460;
 			};
 			buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "__TESTING__" */;
 			compatibilityVersion = "Xcode 3.2";
@@ -381,7 +366,6 @@
 			buildActionMask = 2147483647;
 			files = (
 				F840E1F1165FE0F500CFE078 /* config.xml in Resources */,
-				301BF570109A69640062928A /* www in Resources */,
 				308D05371370CCF300D202BF /* icon-72.png in Resources */,
 				308D05381370CCF300D202BF /* icon.png in Resources */,
 				308D05391370CCF300D202BF /* icon@2x.png in Resources */,
@@ -404,19 +388,19 @@
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
-		304B58A110DAC018002A0835 /* Touch www folder */ = {
+		304B58A110DAC018002A0835 /* Copy www directory */ = {
 			isa = PBXShellScriptBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 			);
 			inputPaths = (
 			);
-			name = "Touch www folder";
+			name = "Copy www directory";
 			outputPaths = (
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "touch -cm ${PROJECT_DIR}/www";
+			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)";
 		};
 /* End PBXShellScriptBuildPhase section */
 
@@ -482,7 +466,6 @@
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				CLANG_ENABLE_OBJC_ARC = NO;
-				CLANG_WARN_OBJCPP_ARC_ABI = YES;
 				COPY_PHASE_STRIP = NO;
 				GCC_DYNAMIC_NO_PIC = NO;
 				GCC_OPTIMIZATION_LEVEL = 0;
@@ -502,7 +485,6 @@
 			buildSettings = {
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				CLANG_ENABLE_OBJC_ARC = NO;
-				CLANG_WARN_OBJCPP_ARC_ABI = YES;
 				COPY_PHASE_STRIP = YES;
 				GCC_PRECOMPILE_PREFIX_HEADER = YES;
 				GCC_PREFIX_HEADER = "__TESTING__/__TESTING__-Prefix.pch";
@@ -519,11 +501,16 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				GCC_C_LANGUAGE_STANDARD = c99;
 				GCC_THUMB_SUPPORT = NO;
 				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				HEADER_SEARCH_PATHS = (
 					"\"$(TARGET_BUILD_DIR)/usr/local/lib/include\"",
@@ -554,11 +541,16 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				GCC_C_LANGUAGE_STANDARD = c99;
 				GCC_THUMB_SUPPORT = NO;
 				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				HEADER_SEARCH_PATHS = (
 					"\"$(TARGET_BUILD_DIR)/usr/local/lib/include\"",
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 6dc7bfc..318f793 100644
--- a/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
+++ b/lib/cordova-ios/bin/templates/project/__TESTING__/Classes/AppDelegate.m
@@ -43,6 +43,11 @@
 
     [cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
 
+    int cacheSizeMemory = 8 * 1024 * 1024; // 8MB
+    int cacheSizeDisk = 32 * 1024 * 1024; // 32MB
+    NSURLCache* sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"];
+    [NSURLCache setSharedURLCache:sharedCache];
+
     self = [super init];
     return self;
 }
@@ -109,4 +114,9 @@
     return supportedInterfaceOrientations;
 }
 
+- (void)applicationDidReceiveMemoryWarning:(UIApplication*)application
+{
+    [[NSURLCache sharedURLCache] removeAllCachedResponses];
+}
+
 @end
diff --git a/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml b/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml
index 721c734..64e7163 100644
--- a/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml
+++ b/lib/cordova-ios/bin/templates/project/__TESTING__/config.xml
@@ -19,7 +19,7 @@
 # under the License.
 #
 -->
-<cordova>
+<widget>
     <preference name="KeyboardDisplayRequiresUserAction" value="true" />
     <preference name="SuppressesIncrementalRendering" value="false" />
     <preference name="UIWebViewBounce" value="true" />
@@ -28,6 +28,8 @@
     <preference name="EnableViewportScale" value="false" />
     <preference name="AutoHideSplashScreen" value="true" />
     <preference name="ShowSplashScreenSpinner" value="true" />
+    <preference name="FadeSplashScreen" value="true" />
+    <preference name="FadeSplashScreenDuration" value=".25" />
     <preference name="MediaPlaybackRequiresUserAction" value="false" />
     <preference name="AllowInlineMediaPlayback" value="false" />
     <preference name="BackupWebStorage" value="cloud" />
@@ -57,4 +59,4 @@
     </plugins>
 
     <access origin="*" />
-</cordova>
+</widget>
diff --git a/lib/cordova-ios/bin/templates/project/cordova/emulate b/lib/cordova-ios/bin/templates/project/cordova/emulate
index ef7198e..f26cb3a 100755
--- a/lib/cordova-ios/bin/templates/project/cordova/emulate
+++ b/lib/cordova-ios/bin/templates/project/cordova/emulate
@@ -1,4 +1,4 @@
-#! /bin/sh
+#! /bin/bash
 #
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
@@ -7,9 +7,9 @@
 # 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
@@ -33,11 +33,8 @@
 XCODEPROJ=$( ls "$PROJECT_PATH" | grep .xcodeproj  )
 PROJECT_NAME=$(basename "$XCODEPROJ" .xcodeproj)
 
-APP_PATH=$1
-
-if [ $# -lt 1 ]; then
-	APP_PATH="$PROJECT_PATH/build/$PROJECT_NAME.app"
-fi
+APP_PATH=${1:-$PROJECT_PATH/build/$PROJECT_NAME.app}
+DEVICE_FAMILY=${2:-${DEVICE_FAMILY:-iphone}}
 
 if [ ! -d "$APP_PATH" ]; then
 	echo "Project '$APP_PATH' is not built. Building."
@@ -51,7 +48,7 @@
 
 # launch using ios-sim
 if which ios-sim >/dev/null; then
-    ios-sim launch "$APP_PATH" --stderr "$CORDOVA_PATH/console.log" --stdout "$CORDOVA_PATH/console.log" &
+    ios-sim launch "$APP_PATH" --family "$DEVICE_FAMILY" --stderr "$CORDOVA_PATH/console.log" --stdout "$CORDOVA_PATH/console.log" &
 else
     echo -e '\033[31mError: ios-sim was not found. Please download, build and install version 1.4 or greater from https://github.com/phonegap/ios-sim into your path. Or "brew install ios-sim" using homebrew: http://mxcl.github.com/homebrew/\033[m'; exit 1;
 fi
diff --git a/lib/cordova-ios/guides/Cordova Custom URL Scheme Handling.md b/lib/cordova-ios/guides/Cordova Custom URL Scheme Handling.md
index 5beb0e4..03c114f 100644
--- a/lib/cordova-ios/guides/Cordova Custom URL Scheme Handling.md
+++ b/lib/cordova-ios/guides/Cordova Custom URL Scheme Handling.md
@@ -34,9 +34,9 @@
         
 You **cannot** launch any interactive features like alerts in the **handleOpenURL** code, if you do, your app will hang. Similarly, you should not call any Cordova APIs in there, unless you wrap it first in a setTimeout call, with a timeout value of zero:
 
-        function handleOpenUrl(url) {
+        function handleOpenURL(url) {
              // TODO: parse the url, and do something 
              setTimeout(function() {
                  // TODO: call some Cordova API here
              }, 0);
-        }
\ No newline at end of file
+        }
diff --git a/package.json b/package.json
index 57b019d..82e4e2e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "cordova",
-  "version": "2.4.10",
+  "version": "2.5.0",
   "preferGlobal": "true",
   "description": "Cordova command line interface tool",
   "main": "cordova",
diff --git a/spec/metadata/blackberry_parser.spec.js b/spec/metadata/blackberry_parser.spec.js
index 6102753..17cb905 100644
--- a/spec/metadata/blackberry_parser.spec.js
+++ b/spec/metadata/blackberry_parser.spec.js
@@ -138,11 +138,6 @@
                 var bb_cfg = fs.readFileSync(blackberry_config, 'utf-8');
                 expect(bb_cfg).not.toBe(www_cfg);
             });
-            it('should inject a reference to webworks.js in index.html', function() {
-                parser.update_www();
-                var index = fs.readFileSync(path.join(blackberry_project_path, 'www', 'index.html'), 'utf-8');
-                expect(index).toMatch(/<script type="text\/javascript" src="js\/webworks.js">/i);
-            });
             it('should call out to util.deleteSvnFolders', function() {
                 var spy = spyOn(util, 'deleteSvnFolders');
                 parser.update_www();