Merge pull request #260 from blackberry/next

0.9.2 release
diff --git a/build/btest.js b/build/btest.js
index 7c36684..4127a85 100644
--- a/build/btest.js
+++ b/build/btest.js
@@ -16,7 +16,6 @@
 module.exports = function () {
     var connect = require('connect'),
         fs = require('fs'),
-        sys = require('sys'),
         utils = require('./build/utils'),
         libs = [],
         tests = [],
@@ -57,6 +56,6 @@
 
     app.listen(3000);
 
-    sys.puts("Test Server running on:");
-    sys.puts("http://127.0.0.1:3000");
+    process.stdout.write("Test Server running on:");
+    process.stdout.write("http://127.0.0.1:3000");
 };
diff --git a/build/build.js b/build/build.js
index 122e816..41276c3 100644
--- a/build/build.js
+++ b/build/build.js
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-var sys = require('sys'),
-    fs = require('fs'),
+var fs = require('fs'),
     jWorkflow = require('jWorkflow'),
     quotes = require('./build/quotes'),
     pack = require('./build/pack'),
@@ -25,11 +24,11 @@
 
 function _done(error) {
     if (error) {
-        sys.puts(fs.readFileSync(__dirname + "/../thirdparty/fail.txt", "utf-8"));
-        sys.puts(error);
+        process.stdout.write(fs.readFileSync(__dirname + "/../thirdparty/fail.txt", "utf-8"));
+        process.stdout.write(error);
         process.exit(1);
     } else {
-        sys.puts(fs.readFileSync(__dirname + "/../thirdparty/dredd.txt", "utf-8"));
+        process.stdout.write(fs.readFileSync(__dirname + "/../thirdparty/dredd.txt", "utf-8"));
         quotes.random();
         process.exit();
     }
diff --git a/build/build/compress.js b/build/build/compress.js
index 3c4e471..be1ae7a 100644
--- a/build/build/compress.js
+++ b/build/build/compress.js
@@ -17,7 +17,6 @@
     _c = require('./conf'),
     utils = require('./utils'),
     childProcess = require('child_process'),
-    sys = require('sys'),
     fs = require('fs'),
     jWorkflow = require('jWorkflow');
 
@@ -30,8 +29,8 @@
             baton.take();
             childProcess.exec('uglifyjs --overwrite ' + file, function (error, stdout, stdin) {
                 if (error) {
-                    sys.puts("Something bad happened. Is uglify-js installed?");
-                    sys.puts(error);
+                    process.stdout.write("Something bad happened. Is uglify-js installed?");
+                    process.stdout.write(error);
                     process.exit(1);
                 } else {
                     baton.pass();
@@ -40,7 +39,7 @@
         });
     }
 
-    sys.puts("compressing...");
+    process.stdout.write("compressing...");
     baton.take();
 
     utils.collect(_c.DEPLOY, files);
diff --git a/build/deploy.js b/build/deploy.js
index 9a20478..6dd68cc 100644
--- a/build/deploy.js
+++ b/build/deploy.js
@@ -16,13 +16,12 @@
 var test = require('./test'),
     lint = require('./lint'),
     build = require('./build'),
-    sys = require('sys'),
     fs = require('fs'),
     fail = fs.readFileSync(__dirname + "/../thirdparty/fail.txt", "utf-8");
 
 function ok(code) {
     if (code || code === 1) {
-        sys.puts(fail);
+        process.stdout.write(fail);
         process.exit(1);
     }
 }
diff --git a/build/lint.js b/build/lint.js
index c1b91a4..32917d1 100644
--- a/build/lint.js
+++ b/build/lint.js
@@ -14,13 +14,18 @@
  * limitations under the License.
  */
 var childProcess = require('child_process'),
-    sys = require('sys'),
     fs = require('fs');
 
 function _spawn(proc, args, done) {
+    function log(data) {
+        process.stdout.write(new Buffer(data).toString("utf-8"));
+    }
+
     var cmd = childProcess.spawn(proc, args);
-    cmd.stdout.on('data', sys.print);
-    cmd.stderr.on('data', sys.print);
+
+    cmd.stdout.on('data', log);
+    cmd.stderr.on('data', log);
+
     if (done) {
         cmd.on('exit', done);
     }
diff --git a/build/lint/reporter.js b/build/lint/reporter.js
index accd137..93d2325 100644
--- a/build/lint/reporter.js
+++ b/build/lint/reporter.js
@@ -15,8 +15,7 @@
  */
 module.exports = {
     reporter: function (results) {
-        var sys = require('sys'),
-            len = results.length,
+        var len = results.length,
             str = '',
             file, error;
 
@@ -27,7 +26,7 @@
                 error.character + ', ' + error.reason + '\n';
         });
 
-        sys.puts(len > 0 ? (str + "\n" + len + ' error' + ((len === 1) ? '' : 's\n')) : "Lint Free!\n");
+        process.stdout.write(len > 0 ? (str + "\n" + len + ' error' + ((len === 1) ? '' : 's\n')) : "Lint Free!\n");
 
         process.exit(len > 2 ? 1 : 0);
     }
diff --git a/build/stats.js b/build/stats.js
index 3c08674..d20ff0b 100644
--- a/build/stats.js
+++ b/build/stats.js
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 module.exports = function () {
-    var sys = require('sys'),
-        libs = [],
+    var libs = [],
         tests = [],
         total_lines = 0,
         total_loc = 0,
@@ -52,9 +51,9 @@
                         .replace(/^.*lib\/ripple\/?/, '')
                         .replace(/^.*test\//, '');
 
-            sys.puts("| " + file + spaces(59 - file.length) + "| " +
+            process.stdout.write("| " + file + spaces(59 - file.length) + "| " +
                     lines + spaces(7 - String(lines).length) + "| " +
-                    loc + spaces(7 - String(loc).length) + "|");
+                    loc + spaces(7 - String(loc).length) + "|\n");
 
             callback(lines, loc);
         }
@@ -77,9 +76,9 @@
     libs.sort();
     tests.sort();
 
-    sys.puts("+------------------------------------------------------------+--------+--------+");
-    sys.puts("| Lib                                                        | Lines  | LOC    |");
-    sys.puts("+------------------------------------------------------------+--------+--------+");
+    process.stdout.write("+------------------------------------------------------------+--------+--------+\n");
+    process.stdout.write("| Lib                                                        | Lines  | LOC    |\n");
+    process.stdout.write("+------------------------------------------------------------+--------+--------+\n");
 
     libs.forEach(function (lib) {
         parseFile(lib, function (lines, loc) {
@@ -88,15 +87,15 @@
         });
     });
 
-    sys.puts("+------------------------------------------------------------+--------+--------+");
-    sys.print("| Total                                                      |");
-    sys.print(" " + lib_lines + spaces(7 - String(lib_lines).length) + "|");
-    sys.puts(" " + lib_loc + spaces(7 - String(lib_loc).length) + "|");
-    sys.puts("+------------------------------------------------------------+--------+--------+");
+    process.stdout.write("+------------------------------------------------------------+--------+--------+\n");
+    process.stdout.write("| Total                                                      |");
+    process.stdout.write(" " + lib_lines + spaces(7 - String(lib_lines).length) + "|");
+    process.stdout.write(" " + lib_loc + spaces(7 - String(lib_loc).length) + "|\n");
+    process.stdout.write("+------------------------------------------------------------+--------+--------+\n");
 
-    sys.puts("+------------------------------------------------------------+--------+--------+");
-    sys.puts("| Tests                                                      | Lines  | LOC    |");
-    sys.puts("+------------------------------------------------------------+--------+--------+");
+    process.stdout.write("+------------------------------------------------------------+--------+--------+\n");
+    process.stdout.write("| Tests                                                      | Lines  | LOC    |\n");
+    process.stdout.write("+------------------------------------------------------------+--------+--------+\n");
 
     tests.forEach(function (test) {
         parseFile(test, function (lines, loc) {
@@ -105,23 +104,23 @@
         });
     });
 
-    sys.puts("+------------------------------------------------------------+--------+--------+");
-    sys.print("| Total                                                      |");
-    sys.print(" " + test_lines + spaces(7 - String(test_lines).length) + "|");
-    sys.puts(" " + test_loc + spaces(7 - String(test_loc).length) + "|");
-    sys.puts("+------------------------------------------------------------+--------+--------+");
+    process.stdout.write("+------------------------------------------------------------+--------+--------+\n");
+    process.stdout.write("| Total                                                      |");
+    process.stdout.write(" " + test_lines + spaces(7 - String(test_lines).length) + "|");
+    process.stdout.write(" " + test_loc + spaces(7 - String(test_loc).length) + "|\n");
+    process.stdout.write("+------------------------------------------------------------+--------+--------+\n");
 
     total_lines = lib_lines + test_lines;
     total_loc = lib_loc + test_loc;
     testsOverLib = (lib_loc / test_loc).toFixed(2);
     emptySpace = total_lines - total_loc;
 
-    sys.puts("+------------------------------------------------------------+--------+--------+");
-    sys.puts("| Stats                                                                        |");
-    sys.puts("+------------------------------------------------------------+--------+--------+");
-    sys.puts("| lines: " + total_lines + spaces(70 - String(total_lines).length) + "|");
-    sys.puts("| loc: " + total_loc + spaces(72 - String(total_loc).length) + "|");
-    sys.puts("| lib/test (loc): " + testsOverLib + spaces(61 - String(testsOverLib).length) + "|");
-    sys.puts("| comments & empty space: " + emptySpace + spaces(53 - String(emptySpace).length) + "|");
-    sys.puts("+------------------------------------------------------------+--------+--------+");
+    process.stdout.write("+------------------------------------------------------------+--------+--------+\n");
+    process.stdout.write("| Stats                                                                        |\n");
+    process.stdout.write("+------------------------------------------------------------+--------+--------+\n");
+    process.stdout.write("| lines: " + total_lines + spaces(70 - String(total_lines).length) + "|\n");
+    process.stdout.write("| loc: " + total_loc + spaces(72 - String(total_loc).length) + "|\n");
+    process.stdout.write("| lib/test (loc): " + testsOverLib + spaces(61 - String(testsOverLib).length) + "|\n");
+    process.stdout.write("| comments & empty space: " + emptySpace + spaces(53 - String(emptySpace).length) + "|\n");
+    process.stdout.write("+------------------------------------------------------------+--------+--------+\n");
 };
diff --git a/build/test.js b/build/test.js
index 1af3d1e..fbd335a 100644
--- a/build/test.js
+++ b/build/test.js
@@ -13,6 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+var jsdom = require('jsdom'),
+    fs = require('fs'),
+    jWorkflow = require('jWorkflow'),
+    jasmine = require('./test/jasmine-node'),
+    childProcess = require('child_process'),
+    nodeXMLHttpRequest = require(__dirname + '/../thirdparty/node-XMLHttpRequest/XMLHttpRequest').XMLHttpRequest;
+
 function _extraMocks() {
     global.screen = {
         height: 1600,
@@ -20,20 +27,16 @@
         width: 1200,
         availWidth: 1200
     };
-    global.XMLHttpRequest = window.XMLHttpRequest = require(__dirname +
-        '/../thirdparty/node-XMLHttpRequest/XMLHttpRequest').XMLHttpRequest;
 
+    global.XMLHttpRequest = window.XMLHttpRequest = nodeXMLHttpRequest;
     require(__dirname + "/../thirdparty/Math.uuid");
-
-    global.jWorkflow = require('jWorkflow');
+    global.jWorkflow = jWorkflow;
 
     window.navigator.userAgent = "foo";
     window.navigator.geolocation = {};
     window.navigator.javaEnabled = function () {};
 
-    global.location = window.location = {
-        protocol: "http"
-    };
+    global.location = window.location = {protocol: "http"};
     global.NamedNodeMap = function () {
         return [];
     };
@@ -41,9 +44,7 @@
 }
 
 function _setupEnv(ready) {
-    var jsdom = require('jsdom'),
-        fs = require('fs'),
-        layout = fs.readFileSync(__dirname + "/../ext/assets/index.html", "utf-8"),
+    var layout = fs.readFileSync(__dirname + "/../ext/assets/index.html", "utf-8"),
         thirdparty = [
             __dirname + "/../thirdparty/jquery.js",
             __dirname + "/../thirdparty/jquery.ui.js"
@@ -64,20 +65,14 @@
 
         _extraMocks();
 
-        ready();
+        childProcess.exec('cp -rf lib/ripple node_modules/ripple && ' +
+                          'cp -f lib/ripple.js node_modules/ripple.js', ready);
     });
 }
 
 module.exports = function (done, custom) {
-    var jasmine = require('jasmine-node'),
-        verbose = false,
-        colored = false,
-        specs = __dirname + "/../" + (custom ? custom : "test");
-
-    require.paths.push(__dirname + "/../lib/");
-
     //HACK: this should be  taken out if our pull request in jasmine is accepted.
-    jasmine.Matchers.prototype.toThrow = function (expected) {
+    jasmine.core.Matchers.prototype.toThrow = function (expected) {
         var result = false,
             exception,
             not = this.isNot ? "not " : "";
@@ -95,12 +90,12 @@
                 result = expected(exception);
             }
             else {
-                result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
+                result = (expected === jasmine.core.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
             }
         }
 
         this.message = function () {
-            if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
+            if (exception && (expected === jasmine.core.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
                 return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
             } else {
                 return "Expected function to throw an exception.";
@@ -111,17 +106,13 @@
     };
 
     _setupEnv(function () {
-        for (var key in jasmine) {
-            if (Object.prototype.hasOwnProperty.call(jasmine, key)) {
-                global[key] = jasmine[key];
-            }
-        }
+        var targets = __dirname + "/../" + (custom ? custom : "test");
 
-        jasmine.executeSpecsInFolder(specs, function (runner, log) {
+        jasmine.run(targets.split(' '), function (runner) {
             var failed = runner.results().failedCount === 0 ? 0 : 1;
             setTimeout(function () {
                 (typeof done !== "function" ? process.exit : done)(failed);
             }, 10);
-        }, verbose, colored);
+        });
     });
 };
diff --git a/build/test/jasmine-node.js b/build/test/jasmine-node.js
new file mode 100644
index 0000000..77c6d76
--- /dev/null
+++ b/build/test/jasmine-node.js
@@ -0,0 +1,106 @@
+/*
+ *  Copyright 2011 Research In Motion Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var utils = require('./../build/utils'),
+    jasmine = require(__dirname + '/../../thirdparty/jasmine/lib/jasmine-core/jasmine');
+
+function run(targets, done) {
+    var suites = [],
+        errors = '',
+        suitesLogged = 0,
+        env = jasmine.jasmine.getEnv(),
+        reporter = new jasmine.jasmine.Reporter(),
+        started;
+
+    Object.keys(jasmine).forEach(function (key) {
+        global[key] = jasmine[key];
+    });
+
+    reporter.reportRunnerStarting = function (runner) {
+        started = new Date().getTime();
+    };
+
+    reporter.reportRunnerResults = function (runner) {
+        var results = runner.results(),
+            tests = runner.suites(),
+            finished = (new Date().getTime() - started) / 1000,
+            msg = '\n\n';
+
+        msg += 'Finished in ' + finished + ' seconds\n';
+        msg += suites.length + ' suite' + ((suites.length === 1) ? '' : 's') + ', ';
+        msg += tests.length + ' test' + ((suites.length === 1) ? '' : 's') + ', ';
+        msg += results.totalCount + ' assertion' + ((results.totalCount === 1) ? '' : 's') + ', ';
+        msg += results.failedCount + ' failure' + ((results.failedCount === 1) ? '' : 's') + '\n';
+
+        process.stdout.write(msg);
+        process.stdout.write('\n' + errors);
+
+        done(runner);
+    };
+
+    reporter.reportSuiteResults = function (suite) {
+        var results = suite.results(),
+            s = suite,
+            p = [],
+            description;
+
+        while (s) {
+            p.unshift(s.description);
+            s = s.parentSuite;
+        }
+
+        description = p.join(' ');
+
+        results.items_.forEach(function (spec) {
+            if (spec.failedCount > 0 && spec.description) {
+                errors += description + '\n';
+
+                spec.items_.forEach(function (test) {
+                    errors += '  it ' + spec.description + '\n';
+                    errors += '    message: ' + test.message + '\n';
+                    errors += '    trace: ' + test.trace.stack + '\n';
+                });
+
+                errors += '\n';
+            }
+        });
+    };
+
+    reporter.reportSpecResults = function (spec) {
+        suitesLogged++;
+
+        process.stdout.write(spec.results().passed() ? '.' : 'F');
+
+        if (suitesLogged % 40 === 0) {
+            process.stdout.write('\n');
+        }
+    };
+
+    env.updateInterval = 1000;
+    env.addReporter(reporter);
+
+    targets.forEach(function (target) {
+        utils.collect(target, suites);
+    });
+
+    suites.forEach(require);
+
+    env.execute();
+}
+
+module.exports = {
+    run: run,
+    core: jasmine.jasmine
+};
diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md
new file mode 100644
index 0000000..340f690
--- /dev/null
+++ b/doc/CHANGELOG.md
@@ -0,0 +1,561 @@
+## v0.9.1 - November 11, 2011
+
+* Added remote web inspector option for WebWorks and WebWorks TabletOS platforms, which is disabled by default.
+* Listen for AppCache updateready events and reload accordingly.
+* Bootstrap addEventListener hijacker dies if registered callback throws exception.
+* Added a module (dbfs) to remove dependency on File API for blackberry.io.{dir|file} (for the time being).
+* Added blackberry.io.dir.appDirs property for tablet and improved filesystem initialization to include directories expected for both tablet and handset.
+* (Hotfix) window load event handlers are not triggered when navigating inside app container (i.e. inside iframe). See [Issue #190](https://github.com/blackberry/Ripple-UI/issues/190).
+
+## v0.9.0 - October 18, 2011
+
+* Added Omnibar plugin to web build
+* Removed vodaphone, opera, wac platforms
+* Added agnostic filesystem api (thin wrapper for W3C File API)
+* Added support for blackberry.io.file and blackberry.io.dir (including blackberry.utils.stringToBlog and blobtoString)
+* Added APIs for blackberry.app.event.onSwipeDown and blackberry.app.event.onSwipeStart for WebWorks Tablet
+* Added support for manually firing events in the PhoneGap Events API
+* Added various BB device skins
+* Add controls for BB build and deploy service
+* Support clientX property in touch events
+* Added cache.manifest support to web build
+* (Fix) [WebWorks] bb.invoke.invoke launches undefined application for CameraArguments
+* (Fix) [WebWorks] sms.isListeningForMessage should be settable
+* (Fix) [WebWorks] bb.app issues
+* (Fix) [WebWokrs] bb.ui.menu issues
+* (Fix) [PhoneGap] When successfully removing a contact, a list of contacts is incorrectly returned
+* (Fix) [PhoneGap] When saving a contact, the returned list is incorrect
+* (Fix) [WebWorks-TabletOS] bb.invoke Browser: URLs do not support certain protocols
+* (Fix) [WebWorks-TabletOS] bb.system.hasPermission() generates exception
+* (Fix) [WebWorks-TabletOS] - blackberry.ui.dialog.standard/customAskAsync settings parameter does not work
+* (Fix) [WebWorks-TabletOS] - blackberry.ui.dialog missing some constant definitions
+* (Fix) [WebWorks/WebWorks-TabletOS] Duplicate versions in platform version select dropdown
+* (Fix) WebWorks-TabletOS platform initializes UI plugins that are specific to WebWorks
+* (Fix) The Back Button on a Device Skin only works on WebWorks platforms
+* (Fix) [WebWorks] blackberry.invoke.invoke generates exceptions
+* (Fix) [WebWorks] blackberry.identity issues
+* (Fix) [WebWorks] wrong attributes validation in config.xml for rim:transitionEffect
+* (Fix) [PhoneGap] contacts.find can not return all contact fields when given "*" for fields param
+* (Fix) [WebWorks] rim:navigation property is not displayed in the config panel
+* (Fix) gamma value in accelerometer UI panel posts no useful information
+* (Fix) [WebWorks] PhoneLogs.addPhoneLogListener does not return a Boolean
+* (Fix) [WebWorks] When a call log record is added, onCallLogAdded is called with an empty object
+* (Fix) [WebWorks] bb.audio does not keep consistence with the supported formats on a device
+* (Fix) [WebWorks-TabletOS] invoke.APP_UPDATE should NOT exist on PlayBook
+* (Fix) [WebWorks-TabletOS] system.setHomeScreenBackground should not exist
+* (Fix) In the accelerometer panel, after rotating the device, then shaking the xAxis automatically resets back to 0
+* (Fix) iFrame shows scroll bars when content overflows
+* (Fix) SMS and Data text boxes too big
+* (Fix) Can't switch to Nokia N97 (Touch) Device
+* (Fix) Fixed fetching of config.xml relative to application content (on web build)
+
+## v0.6.3 - October 7, 2011
+
+* HOTFIX - Fixed load event not firing on navigation as well as bug with jQuery Mobile
+
+## v0.6.1 - August 23, 2011
+
+* jake build now places compiled folders in pkg/ (vs ../ripple_build)
+* Tweaked bootstrap module to ensure APIs are properly injected when navigating within the iFrame
+* Updated PhoneGap (visually) to 1.0
+* Updated PhoneGap Contacts namespace (to navigator.contacts)
+* Updated PhoneGap Connection API (and deprecated old network API)
+* Fixed W3C Geolocation data values initially being 0
+* Created a WebWorks-TabletOS platform, and split original WebWorks into webworks.tablet, webworks.handset and webworks.core
+* Phone.addPhoneListener called with eventType of 0 (CB_CALL_INITIATED) did not assign the event (webworks.handset)
+* Phone.addPhoneListener returns true when successfully assigned (webworks.handset)
+* CallLog is exposed publicly (webworks.handset)
+* Added WebWorks show and remove Banner APIs to webworks.handset
+* Implemented SystemEvent APIs for webworks.tablet (i.e. Playbook)
+* Fixed onHardwareKey and onCoverageChange events in SystemEvent API for webworks.handset
+* Added the DeviceOrientation W3C APIs (to all platforms)
+* Fixed webworks.core select module to handle -1 and null .max() values
+* Added Invoke API to WebWorks-TabletOS
+* Added .jshintignore file (and added node-jshint --show-non-error option to jake lint)
+
+## v0.6.0 - August 02, 2011
+
+* Fixed WebWorks pim.category to be in correct place (pim.category.XXX vs pim.XXX)
+* Added missing accuracy property to PhoneGap (i.e. W3C) geolocation
+* Removed vendor specific branding from Torch skin
+* Fixed not being able to save any new Contacts in WebWorks
+* Fixed Find in WebWorks
+* Fixed a UI bug causing boolean based device settings to always return true
+* Added W3C geolocation implementation to mobile web platform
+* Added W3C geolocation implementation to WebWorks platform
+* Fixed bug where you could not disable Ripple when auto-enabled
+
+## v0.5.4 - June 27, 2011
+
+* Added Bold 9900 to devices
+* Added ability to bypass and better simulate CORS requests with the --disable-web-security flag (more info coming soon) 
+* Fixed issues with running webworks on the file scheme
+* Fixed generation of uids on blackberry.message.Message
+* Fixed return value of blackberry.message.sms.removeReceiveListener
+* Fixed blackberry.identity.phone.getLineIds
+* Updated our error page to get rid of references to setting the delay (but not the zombies)
+* updated our bootstrap/injection code to be closured better
+
+## v0.5.3 - June 20, 2011
+
+* Added Nexus S to devices
+* Missing Storage UI panel in WAC
+* Added additional apps to launch via invoke (Search, Memo, Java, Calendar, AddressBook)
+* blackberry.app.id returns undefined
+* blackberry.menu cannot set property 'isDefault' of undefined
+* blackberry.app.setHomeScreenIcon doesn't return a bool
+* blackberry.app.setHomeScreenName doesn't return a bool
+* blackberry.invoke breakage (TaskArguments, PhoneArguments, MessageArguments)
+
+## v0.5.2 - May 26, 2011
+
+* Fixed (missed) breakages in a number of WebWorks apis
+
+## v0.5.1 - May 24, 2011
+
+ * Updated the device orientation UI to better support devices that don't support it.
+ * Updated UI plugins so code is not executed if the plugin isn't available 
+ * Updated Ripple to use UglifyJS to compress code 
+ * Added a device default orientation (e.g. Playbook defaults to Landscape) 
+ * Fixed Selected Platform showing as Mobile Web Vdefault type-o
+ * Fixed Playbook image sprite
+ * Fixed Playbook skin, landscape/portrait mismatch 
+ * Fixed UI for handling of Webworks default menu item to be more clear as to which is the default item
+ * Fixed Ripple :: Initialization Finished (Make it so.) being logged twice
+ * Fixed bug where on first run the platform selection buttons were not clickable
+
+## v0.5.0 - May 11, 2011
+
+* Added support for the Webworks Platform
+* Only Webworks APIs listed in the config.xml are available for the app (all are available if there is no config)
+* Removed visual scrollbars for applications that scroll on body
+* Added Device skinning support and added BlackBerry Skins (Torch, Bold, Playbook)
+* Added functional back and menu buttons for (applicable) Blackberry devices (on WebWorks).
+* Implement getAllResponseHeaders on jsonp XHR
+* Mixin platform api methods into their respective objects if they already exist in window, instead of overwriting it (ex. window.navigator on PhoneGap)
+* Use latest jWorkflow (0.4.0)
+* Use latest jQuery (1.6) and jQuery UI (1.8.12)
+* Renamed Webworks version from 1.0.0 to 2.0.0
+* Refactor to use the CommonJS module pattern
+* Added iPad to PhoneGap
+* Fixed XHR to not do CORS if on the same domain
+* Fixed handling of errors and when to show the error page
+* Fixed selected platform showing as Mobile Web Vdefault
+* Fixed Invalid data being put into Geolocation UI
+* Fixed xml config parsing should parse features into appInfo
+* Fixed unreadable (light) background on selected boxes in Chrome ~12
+* Removed PPI Emulation
+* Fixed Playbook user agent string
+* Fixed scrollbars rendering incorrectly on Windows XP
+* When ripple is updated it uses the HTML5 notifications API instead of popping up an annoying window
+
+## v0.4.14 - April 21, 2011 (HOT FIX)
+
+* HOTFIX: Fix bug where loading a Sencha Touch 1.1.0 application caused the emulation window to shift to the left.
+* HOTFIX: Fix bug where XMLHttpRequest.getAllResponseHeaders() was throwing an "unimplemented" exception for jsonp calls.
+
+## v0.4.13 - April 14, 2011 (HOT FIX)
+
+* HOTFIX: Fix bug where loading a Sencha Touch 1.1.0 application caused the emulation window to shift to the left.
+* Update the Ripple product Update page
+
+## v0.4.12 - March 16, 2011 (HOT FIX)
+
+* HOTFIX: Ensured that XHR proxy is not called for non-Cross Origin requests.
+
+## v0.4.11 - March 05, 2011 (HOT FIX)
+
+* Implemented workaround for NS Basic/App Studio that was causing Ripple to crash
+
+## v0.4.10 - Feb 24, 2011 (HOT FIX)
+
+* Fixed first run window bug, selected is now remembered when Ripple loads
+* Fixed proxy redirection bug for XMLHTTPRequest, local URLs were being identified as external URLs
+* Removed view port sizing for iPhone 3g for the PhoneGap platform
+
+## v0.4.9 - Feb 16, 2011
+
+* Split platform selection and device selection into two separate panels
+* Fixed Accelerometer bug ( Gravity FAIL :-) )
+
+## v0.4.8 - Feb 07, 2011
+
+* Added support for:
+    * PhoneGap Compass
+    * PhoneGap.available property
+    * Ability to auto-enable Ripple with "enableripple=true" querystring parameter
+
+* Fixed Accelerometer bug ( Trigonometry FAIL :-) )
+* Removed Storage UI panel for PhoneGap
+
+## v0.4.7 - Jan 28, 2011
+
+* Fixed Messaging.sendMessage validation bug (WAC)
+
+## v0.4.6 - Jan 26, 2011
+
+* Updated notification pane to position over the emulated mobile device
+* Added support for the PhoneGap contacts API
+* Fixed Audio and Video bugs
+* Added UI element in Ripple to deal with Video Player
+
+## v0.4.5 - Jan 14, 2011
+
+* removed tinyhippos prefix from css rules
+* added some more parameter validation to the WAC runtime in PIM, VideoPlayer, AudioPlayer, Camera
+* Added PhoneGap config validation
+* We now display the widget name, version and icon in the infopane on Phonegap based on the config.xml
+* Added the ability to simulate a GPS timeout on WAC and Phonegap
+* Disable ability to enable ripple on a directory listing in the file:/// scheme (security issues)
+* Prevent ripple from injecting itself on non html files (img, js, css, etc)
+* Support for touchstart, touchmove and touchend DOM events.
+
+## v0.4.3 - Dec 22, 2010
+
+* Improved bootup sequence (ripple would present a white screen on bootup)
+* Added support for network.isReachable (PhoneGap)
+* Fixed a bug with Widget.Messaging.createMessage (WAC)
+* Fixed several minor bugs in Widget.PIM (WAC)
+* Instantiable objects in WAC now work as expected with the "instanceof" operator
+* Fixed bug in Widget.Multimedia.Camera.setWindow not working
+
+## v0.4.2 - Dec 16, 2010
+
+* can run without the need of a local webserver
+    * Please run Chrome with the --allow-file-access-from-files command line option for this to work
+    * You need to ensure that the "Allow Access to file URLS" option on the extension page for Ripple
+
+* QuirksMode support for JIL 1.0/1.2 setPreferenceForKey is deprecated.
+* Update Information pane and device information
+* Add in a hardcoded set of Contacts (currently only available after the body.onload)
+* Fix Message class to be constructable
+* DeviceStateInfo.onScreenChangeDimensions should not be supported
+* Add jQuery AOP reference to main license
+* Fixed boolean device settings would always be enabled
+* Widget.Multimedia.AudioPlayer issue: media file not played after play function call.
+* Widget.Multimedia.AudioPlayer open method is now sync
+* Fixes to get Ripple working in Chrome 8/9/10
+* Widget.Messaging.createMessage doesn't return a message object
+* Support instanceof on instance types in WAC
+
+## v0.4.1 - Dec 6, 2010
+
+* Support for new devices in on the mobile web platform:
+    * Blackberry Playbook
+    * Blackberry Torch
+    * Blackberry Bold 97xx
+    * Nokia N8
+
+* Support for new devices on the phonegap platform
+    * Blackberry Torch
+    * Blackberry Bold 97xx
+    * Nokia N8
+    * Palm Pre 2
+
+* Improved injection issues on some sites
+* Fixed error where sites that did fast dom manipulation would corrupt ripple's UI
+* First run window will no longer refresh multiple times
+* Made ripple loading sequence look nicer
+* Added support for geolocation delay to phonegap and vodafone
+* Moved geolocation delay to the geo panel rather than in device settings
+* Tooltip settings will now persist
+* Ripple no longer needs to refresh when navigating links inside the application
+* Fixed some issues with the back button looping when navigating inside the emulated application
+* Fixed a bug where device settings default values would stay true even when unchecked
+* Ripple can now be disabled from lower level directories when enabled from a top level directory
+* fixed emulation of window.screen size properties in screen and window
+* Improvements to the Device Information UI
+
+## v0.4.0 - Nov 30, 2010
+
+* Read our blog post about this release - http://tinyhippos.com/2010/11/30/ripple-0-4-0-released/">here</a>
+* New emulation code
+    * Support for Sencha Applications
+    * Support for jqTouch
+    * Improved support for jQuery Mobile
+    * Faster bootup times
+    * API Objects are now available for use at eval time
+
+* Improved Accelerometer control
+* Added Camera Support to Vodafone
+* Renamed JIL to WAC
+* Renamed Vodafone 360 to Vodafone
+* Changed Phonegap version from 0.9.1 to 0.9
+* Snapping of phone to the side of the browser when hiding the panels
+* Support for emulation of new devices on the mobile web platform:
+    * iPhone 4
+    * Playbook
+    * Nokia N8
+
+* Bug Fixes:
+    * Fixed race condition when enabling ripple.
+    * Fixed cases where dynamically inserted css links were not handled by the emulator.
+    * Style attribute on body tag is no longer removed.
+    * Fixed handling of position fixed
+    * Added a default background (white) for cases where the users markup doesn't have a background colour
+    * Fixed bug where earlier versions of prototype would cause ripple to not load
+
+## v0.3.8 - Nov 19, 2010
+
+* Fixed bug where jQuery mobile alpha 2 wouldn't render
+
+## v0.3.7 - Nov 15, 2010
+
+* JIL: Widget.Multimedia.VideoPlayer support
+* JIL: Widget.Messaging improved support
+* JIL: Widget.Multimedia.Camera support
+* Styling on html tag now fully emulated
+* /virtual/widgethome now automatically mapped to the widgets url
+* Fixed long standing issue with XHR CORs
+
+## v0.3.6 - Oct 26, 2010
+
+* Fixed Geolocation callback failure in DeviceStateInfo (JIL).
+
+## v0.3.5 - Oct 22, 2010
+
+* Improved JIL support
+    * Messaging.createMessage
+    * Messaging.sendMessage (partial)
+    * PIM.CalendarItem
+    * PIM.addCalendarItem
+    * PIM.deleteCalendarItem
+    * PIM.getCalendarItem
+    * PIM.getCalendarItems
+    * PIM.findCalendarItems
+    * PIM.onCalendarItemsFound
+* JIL/Vodafone now have Device Option for delay for onPositionRetrieved
+* window.onload and body onload now handled properly
+* window.onresize now fires properly
+* window.innerHeight/Width now emulated properly
+* Styling on body tag now fully emulated
+* Added a PhoneGap demo widget. See it http://rippledemo.tinyhippos.com/phonegap/index.html
+* Discovered issues in Ripple with prototype.js version 1.6.1 and earlier.
+* Discovered bug: using fixed positioning in css may not result in desired layout in Ripple
+
+## v0.3.4 - Oct 15, 2010
+
+* Improved JIL support:
+    * PIM.AddressBookItem
+    * PIM.createAddressBookItem
+    * PIM.findAddressBookItems
+    * PIM.getAddressBookItem
+    * PIM.getAddressBookItemsCount
+    * PIM.onAddressBookItemsFound
+    * PIM.addAddressBookItem
+    * PIM.deleteAddressBookItem
+* OMGWTFBBQ
+* Mapping to Body tag now fully supported
+* Fixed Language device setting select for UI for Vodafone 360
+
+## v0.3.1 to v0.3.3 - Oct 7, 2010 - Bug fixes
+
+* Ripple failing with 100% CPU usage on Mac OS X
+* Ripple showing scrollbars on body
+* Phonegap deviceready event should fire from document rather then window
+
+## v0.3.0 - Oct 3, 2010
+
+* Added support for PhoneGap
+* Vodafone 360 separated from JIL into its own platform
+* Additional JIL support for specific API support)
+    * DeviceInfo.phoneOS
+    * DeviceInfo.phoneModel
+    * DeviceInfo.phoneManufacturer
+    * DeviceInfo.phoneFirmware
+    * DeviceInfo.phoneSoftware
+    * DeviceStateInfo.language
+    * Telephony.findCallRecords
+    * Telephony.getCallRecord
+    * Telephony.getCallRecordCnt
+    * Telephony.initiateVoiceCall
+    * Telephony.onCallRecordsFound
+    * Telephony.onCallEvent
+
+* Panel arrangements are now saved per platform instead of globally
+* Implemented viewport sizing for various platforms and their devices
+* Switched main persistence to SQLite
+* Added platform select window when initially enabled for a specific URL
+* Modified Platforms panel
+    * Platform select is now platform only. Version select is now separate
+    * Must now click "Change Platform" to trigger the change
+* Accelerometer now has Shake feature (all platforms)
+* Panel panes are collapsible
+* Removed "Update" button from all panels (information is saved automatically)
+* body id/class attributes get emulated properly
+
+## V0.2.4 - August 17th, 2010
+
+* Updated PPI emulation: all assets get sized correctly
+* Added a generic phone wrapper to the emulated widget
+* Optimized Ripple's loading time and package size for better performance
+* Updated the UI panels to only display if they are relevant to the current platform being used
+* Opera - fires "resolution" event when screen resolution/orientation changes
+* JIL - Added support for:
+    * DataNetworkConnectionTypes
+    * DataNetworkInfo.isDataNetworkConnected
+    * DataNetworkInfo.onNetworkConnectionChanged
+    * DataNetworkInfo.getNetworkConnectionName
+    * DataNetworkInfo.networkConnectionType
+    * RadioInfo.isRadioEnabled
+    * RadioInfo.isRoaming
+    * RadioInfo.radioSignalSource
+    * RadioInfo.radioSignalStrengthPercent
+    * RadioInfo.onSignalSourceChange
+    * PowerInfo.onLowBattery
+    * PowerInfo.onChargeLevelChange
+    * PowerInfo.onChargeStateChange
+    * PowerInfo.isCharging
+    * PowerInfo.percentRemaining
+    * Config.setAsWallpaper
+    * Config.setDefaultRingtone
+    * Config.ringtoneVolume
+    * Config.msgRingtoneVolume
+    * Config.vibrationSetting
+* BUG FIX: Changing platform will now refresh Ripple with the correct platform (no longer need to change the device to trigger the change)
+
+## V0.2.2 to V0.2.3 - July 27th, 2010 - Bug Fixes
+
+* Fixed table color not properly inheriting CSS defined color
+* Opera bug Fixed a typo in configuration validation
+* Fixed Background color not being set properly in the widget container
+* JIL bug fixes (AccountInfo.userAccountBalance and DeviceInfo.phoneColorDepthDefault -> was a string not a numerical value)
+
+## V0.2.1 - July 21th, 2010
+
+* Small UI updates, including cleanup and some minor rearranging of the Platform panel
+* Fixed 2 JIL platform bugs
+    * DeviceInfo.totalMemory was a string updated to a number
+    * DeviceStateInfo.availableMemory was a string updated to a number
+
+
+## V0.2.0 - July 19th, 2010
+
+* Added support for the following JIL APIs
+    * Multimedia.getVolume
+    * Multimedia.stopAll
+    * Multimedia.isAudioPlaying
+    * AudioPlayer.open
+    * AudioPlayer.play
+    * AudioPlayer.pause
+    * AudioPlayer.resume
+    * AudioPlayer.stop
+    * AudioPlayer.onStateChange
+    * Device.widgetEngineName
+    * Device.widgetEngineProvider
+    * Device.widgetEngineVersion
+    * Device.vibrate
+    * RadioInfo.isRadioEnabled
+    * RadioInfo.isRoaming
+    * DataNetworkInfo.isDataNetworkConnected
+    * DeviceStateInfo.keypadLightOn
+    * DeviceStateInfo.backLightOn
+    * DeviceStateInfo.availableMemory
+    * DeviceStateInfo.audioPath
+    * DeviceStateInfo.processorUtilizationPercent
+    * DeviceInfo.totalMemory
+    * DeviceInfo.phoneColorDepthDefault
+    * AccountInfo.phoneUserUniqueId
+    * AccountInfo.phoneMSISDN
+    * AccountInfo.phoneOperatorName
+    * AccountInfo.userAccountBalance
+    * AccountInfo.userSubscriptionType
+    * Account.phoneName
+    * Account.phoneId
+
+* Update UI for themes to allow for better readability
+* Implemented basic virtual file system
+* Various paper-cuts and small bug fixes
+
+## V0.1.186 - June 24th, 2010
+
+* You can now do full cross domain XMLHttpRequests using both GET and POST methods as well as chose whether you want to make those requests synchronously or asynchronously
+* We have added themes to Ripple... I won't tell you where they are, you'll have to go exploring a little.
+* Updated the move and collapse controls for our panels. They should be more intuitive now
+* Move our change log to our documentation site
+* Updated the documentation site
+* Updated the Welcome/Version update popup screen
+
+## V0.1.158 - June 7th, 2010
+
+* Bug fix: Persistence race condition, causing preferences to not save properly when widget first loaded.
+* Added update and welcome popup notifications to inform user of automatic updates.
+* Updated the Ripple logo.
+
+## V0.1.137 - May 26th, 2010
+
+* JIL 1.2.1 :: Added simple support for Widget.Device.DeviceStateInfo.AccelerometerInfo.
+* JIL 1.2.1 :: Added support for config defined preferences.
+* JIL 1.2.1 :: Added support for <strong>read-only</strong> config defined preferences.
+* Preferences are now widget specific. Preferences saved in one widget will not show up in another.
+* Minor CSS fixes for Notifications.
+
+## V0.1.97 - May 17th, 2010
+
+* Updated the way widget gets encapsulated and CSS styles applied. Should fix some widget display bugs.
+* Fixed problem with JSON to ensure that internal version did not get overridden, but loaded widget.
+* Fixed OpenURL for both JIL and Opera.
+* Other small bug fixes.
+
+## V0.1.6 - V0.1.44
+
+* Fixed close button on error notifications to actually work.
+* Added support for widget DOM injected content (for document.body), to ensure that the content gets inserted into the widget container as opposed to into the Body node.
+* Added support for widget screen sizing based on available pixels (i.e. view port size) as opposed to device screen size.
+* Added new devices to JIL 1.2.1 framework based on the list provided by Vodafone.
+* Added warning if config.xml does not exist for a widget the requires it.
+* Added warning if widget version does not match that of selected platform.
+* Added support for screen.height, screen.availHeight (both the have the same value for now).
+* Added support for screen.width, screen.availWidth  (both the have the same value for now).
+* Will remember the state of the tool tips (on or off)
+* Fixed zoom level on GPS map
+
+## V0.1.6
+
+* Added support for Widget.Device.DeviceStateInfo.onScreenChangeDimensions and Widget.onMaximize callback functions being
+    called when device orientation is changed (i.e. going from Landscape to Portrait).
+* Fixed a typo in link to demo widget 
+* Added the What's New panel
+
+## V0.1.3
+
+* Updated PPI emulation to be optional, user must now select this feature.
+* Updated Persistence "clear all" to not remove Ripple application state info. (bug fix) 
+
+## V0.1.2
+
+* Added Options page with information on each release as well as providing helpful information.
+* Added link in the Ripple popup page to the Demo widget providing a step by step walk through the features available in Ripple
+
+## V0.1.1
+
+* Completed JIL API implementation. All unsupported methods will raise appropriate Exceptions. 
+
+## V0.1.0
+
+* Supports general web app development.
+* Supports Opera and JIL (subset of API) mobile widget platforms.
+* Widget.onWakeup
+* Widget.onMaximize
+* Widget.onFocus
+* Widget.onRestore
+* Widget.setPreferenceForKey
+* Widget.preferenceForKey
+* Widget.openUrl
+* Widget.ExceptionTypes
+* Widget.Exception
+* Widget.Device.widgetEngineName =&gt; Static non-editable at this time
+* Widget.Device.widgetEngineProvider =&gt; Static non-editable at this time
+* Widget.Device.widgetEngineVersion =&gt; Static non-editable at this time
+* Widget.Device.getAvailableApplications =&gt; Static non-editable at this time
+* Widget.Device.launchApplication
+* Widget.Device.AccountInfo.phoneUserUniqueId =&gt; Static non-editable at this time
+* Widget.Device.AccountInfo.phoneMSISDN =&gt; Static non-editable at this time
+* Widget.Device.AccountInfo.phoneOperatorName =&gt; Static non-editable at this time
+* Widget.Device.AccountInfo.userAccountBalance =&gt; Static non-editable at this time
+* Widget.Device.AccountInfo.userSubscriptionType =&gt; Static non-editable at this time
+* Widget.Device.DeviceStateInfo.onPositionRetrieved
+* Widget.Device.DeviceStateInfo.requestPositionInfo
+* Widget.Device.PositionInfo
+* Widget.Device.RadioInfo.RadioSignalSourceTypes
+* Widget.Device.ApplicationTypes
diff --git a/ext/chromium/views/update.html b/ext/chromium/views/update.html
index aff56fb..a7f00cc 100644
--- a/ext/chromium/views/update.html
+++ b/ext/chromium/views/update.html
@@ -28,17 +28,14 @@
                 var metaData = chrome.extension.getBackgroundPage().tinyHippos.Background.metaData();
                 document.write(metaData.justInstalled ? "Welcome to Ripple" : "Ripple has been updated");
             </script></h2>
-
-            <p><script type="text/javascript" charset="utf-8">
-                var html = "";
-                if (metaData.justInstalled) {
-                    html = "Visit our <a href=\"http://developer.blackberry.com/html5/documentation\" target=\"_blank\">documentation site</a> to get started.";
-                } else {
-                    html = "See what's new in <a href=\"http://rippledocs.tinyhippos.com/index.html#changelog\"" +
-                        " target=\"_blank\">v" + metaData.version + "</a>.";
-                }
-                document.write(html);
-            </script></p>
+            <p>
+                The Ripple Chrome Extension will be discontinued on Feb 29th, 2012. Please visit our
+                HTML5 site and download the new version of Ripple at the link below:
+            </p>
+            <p>
+                <a href="http://developer.blackberry.com/html5/download/ripple" target="_blank">Download Ripple</a>
+            </p>
+            <p>Read all about the new release of Ripple <a href="http://devblog.blackberry.com/2011/12/ripple-beta-refresh-download/" target="_blank">here</a></p>
         </div>
     </body>
 </html>
diff --git a/lib/ripple/bootstrap.js b/lib/ripple/bootstrap.js
index 4455fba..7a5bef9 100644
--- a/lib/ripple/bootstrap.js
+++ b/lib/ripple/bootstrap.js
@@ -41,34 +41,7 @@
                 } else {
                     _bindObjects(frame);
                 }
-            }, 1),
-            ael = frame.contentWindow.addEventListener,
-            handlers = {
-                load: [],
-                DOMContentLoaded: []
-            };
-
-        //HACK: This is to get around a bug in webkit where it doesn't seem to
-        //      fire the load handlers when we readd the iframe back into the DOM
-        //      https://github.com/blackberry/Ripple-UI/issues/190
-        frame.contentWindow.addEventListener = function (event, handler) {
-            if (handlers[event]) {
-                handlers[event].push(handler);
-            }
-            else {
-                ael.apply(this, arguments);
-            }
-        };
-
-        frame.fireHandlers = function (event) {
-            handlers[event].forEach(function (handler) {
-                try {
-                    return handler && handler({});
-                } catch (e) {
-                    _console.error(e);
-                }
-            });
-        };
+            }, 1);
     });
 
     return frame;
@@ -99,8 +72,6 @@
             document.querySelector("#ui").removeChild(bootLoader);
         }
 
-        frame.fireHandlers("DOMContentLoaded");
-        frame.fireHandlers("load");
         event.trigger("TinyHipposLoaded");
 
         _cleanBody();
diff --git a/lib/ripple/deviceMotionEmulator.js b/lib/ripple/deviceMotionEmulator.js
index 6898e77..563dd3e 100644
--- a/lib/ripple/deviceMotionEmulator.js
+++ b/lib/ripple/deviceMotionEmulator.js
@@ -42,6 +42,7 @@
         }
     };
 }
+
 _self = {
     init: function (frame) {
         var widgetWindow = frame.contentWindow,
@@ -65,14 +66,14 @@
                 _motion.set(callback);
             }
             else {
-                add(event, callback);
+                add.apply(widgetWindow, arguments);
             }
         };
 
         widgetWindow.removeEventListener = function (event, callback) {
             _motion.unbind(callback);
             _orientation.unbind(callback);
-            remove(callback);
+            remove.apply(widgetWindow, arguments);
         };
 
         event.on("DeviceMotionEvent", function (motion) {
diff --git a/lib/ripple/platform/webworks.core/2.0.0/client/utils.js b/lib/ripple/platform/webworks.core/2.0.0/client/utils.js
index 3c55afd..c426327 100644
--- a/lib/ripple/platform/webworks.core/2.0.0/client/utils.js
+++ b/lib/ripple/platform/webworks.core/2.0.0/client/utils.js
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-var _hate = {};
+var _blobs = {};
 
 function _blobBuilder() {
     var BlobBuilder = BlobBuilder || WebKitBlobBuilder;
@@ -105,19 +105,20 @@
     },
 
     blobToString: function (blob, encoding) {
-        return _hate[blob.uuid];
+        return _blobs[blob.id];
     },
 
     stringToBlob: function (string, encoding) {
-        var uuid = Math.uuid(undefined, 16),
+        var id = Math.uuid(undefined, 16),
             blob = _blobBuilder(),
             finalBlob;
 
-        _hate[uuid] = string;
+        _blobs[id] = string;
         blob.append(string);
 
         finalBlob = blob.getBlob();
-        finalBlob.uuid = uuid;
+        finalBlob.id = id;
+        finalBlob.length = finalBlob.size;
 
         return finalBlob;
     }
diff --git a/lib/ripple/platform/webworks.core/2.0.0/fsCache.js b/lib/ripple/platform/webworks.core/2.0.0/fsCache.js
index e5acff0..4bceff9 100644
--- a/lib/ripple/platform/webworks.core/2.0.0/fsCache.js
+++ b/lib/ripple/platform/webworks.core/2.0.0/fsCache.js
@@ -52,7 +52,7 @@
     _createPath("/accounts/1000/appdata/emulatedapp/shared/downloads");
     _createPath("/accounts/1000/appdata/emulatedapp/shared/misc");
     _createPath("/accounts/1000/appdata/emulatedapp/shared/music");
-    _createPath("/accounts/1000/appdata/emulatedapp/shared/photo");
+    _createPath("/accounts/1000/appdata/emulatedapp/shared/photos");
     _createPath("/accounts/1000/appdata/emulatedapp/shared/print");
     _createPath("/accounts/1000/appdata/emulatedapp/shared/videos");
     _createPath("/accounts/1000/appdata/emulatedapp/shared/voice");
@@ -147,7 +147,6 @@
     file: {
         exists: function (path) {
             var entry = _get(path);
-            fs.stat(path, function () {}, _fsError);
             return !!(entry && !entry.isDirectory);
         },
 
@@ -269,7 +268,6 @@
 
         exists: function (path) {
             var entry = _get(path);
-            fs.stat(path, function () {}, _fsError);
             return !!(entry && entry.isDirectory);
         },
 
@@ -294,10 +292,6 @@
             var entry = _get(path),
                 array = path.split("/");
 
-            fs.stat(path, function (entry) {
-                entry.getParent(function (p) {}, _fsError);
-            }, _fsError);
-
             return entry ? array.splice(0, array.length - 1).join("/") || "/" : null;
         },
 
diff --git a/lib/ripple/ui/plugins/about-dialog/dialog.html b/lib/ripple/ui/plugins/about-dialog/dialog.html
index 48ef325..7dc419a 100644
--- a/lib/ripple/ui/plugins/about-dialog/dialog.html
+++ b/lib/ripple/ui/plugins/about-dialog/dialog.html
@@ -1,14 +1,14 @@
 <div id="about-dialog" class="ui-state-default">
     <div class="about-logo"></div>
     <span><strong>Ripple Mobile Emulator</strong>
-        <span id="about-dialog-ripple-version">(v0.9.0)</span>
+        <span id="about-dialog-ripple-version">(v0.9.1)</span>
     </span><br/>
     <ul style="font-size: 0.8em">
         <li>Ripple UI 
             <span id="about-dialog-ripple-ui-version">(checking...)</span>
         </li>
         <li>Ripple Framework 
-            <span id="about-dialog-ripple-framework-version">(v0.9.0)</span>
+            <span id="about-dialog-ripple-framework-version">(v0.9.1)</span>
         </li>
         <li>Ripple Build &amp; Deploy 
             <span id="about-dialog-ripple-build-deploy-version">(checking...)</span>
diff --git a/lib/ripple/ui/plugins/settings-dialog.js b/lib/ripple/ui/plugins/settings-dialog.js
index 2e6a78c..c08c108 100644
--- a/lib/ripple/ui/plugins/settings-dialog.js
+++ b/lib/ripple/ui/plugins/settings-dialog.js
@@ -417,7 +417,7 @@
                             settings["bundle_number"] = $("#settings-field-bundle_number").val(parseInt($("#settings-field-bundle_number").val(), 10) + 1).val();
                             _settings.save(settings);
                         }
-                        notifications.openNotification("normal", "Build succeded!");
+                        notifications.openNotification("normal", "Build succeeded!");
                         _endProgress();
                     }
                 }
diff --git a/lib/ripple/utils.js b/lib/ripple/utils.js
index b26c2d0..c5ea124 100644
--- a/lib/ripple/utils.js
+++ b/lib/ripple/utils.js
@@ -175,14 +175,15 @@
     rippleLocation: function () {
         var loc = self.location(),
             parts = loc.pathname.replace(/\/$/, "").split("/"),
-            base = "";
+            base = "",
+            port = loc.port ? ":" + loc.port : "";
 
         if (parts[parts.length - 1].indexOf(".") !== -1) {
             parts = parts.splice(0, parts.length - 1);
         }
         base = parts.join("/");
 
-        return loc.protocol + "//" + loc.hostname + base + "/";
+        return loc.protocol + "//" + loc.hostname + port + base + "/";
     },
 
     arrayContains: function (array, obj) {
diff --git a/package.json b/package.json
index b2c9b3b..fa4af05 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "ripple",
-  "version": "0.9.1",
+  "version": "0.9.2",
   "description": "A browser based html5 mobile application development and testing tool",
   "homepage": "http://github.com/blackberry/Rippe-UI",
   "author": {
@@ -17,7 +17,6 @@
     "connect": "1.7.x",
     "argsparser": "0.0.x",
     "jsdom": "0.2.4",
-    "jasmine-node": "1.0.7",
     "jWorkflow": "*"
   },
   "bundledDependencies": [
diff --git a/test/unit/deviceMotionEmulator.js b/test/unit/deviceMotionEmulator.js
new file mode 100644
index 0000000..2a7eca8
--- /dev/null
+++ b/test/unit/deviceMotionEmulator.js
@@ -0,0 +1,58 @@
+/*
+ *  Copyright 2011 Research In Motion Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+describe("deviceMotionEmulator", function () {
+    var event = require('ripple/event'),
+        deviceMotionEmulator = require('ripple/deviceMotionEmulator');
+
+    beforeEach(function () {
+        spyOn(event, "on");
+    });
+
+    afterEach(function () {
+    });
+
+    describe("when initializing", function () {
+        it("properly masks frame.addEventListener", function () {
+            var addEventListener = jasmine.createSpy(),
+                callback = jasmine.createSpy(),
+                frame = {
+                    contentWindow: {
+                        addEventListener: addEventListener
+                    }
+                };
+
+            deviceMotionEmulator.init(frame);
+            frame.contentWindow.addEventListener('load', callback, false);
+
+            expect(addEventListener).toHaveBeenCalledWith('load', callback, false);
+        });
+
+        it("properly masks frame.removeEventListener", function () {
+            var removeEventListener = jasmine.createSpy(),
+                callback = jasmine.createSpy(),
+                frame = {
+                    contentWindow: {
+                        removeEventListener: removeEventListener
+                    }
+                };
+
+            deviceMotionEmulator.init(frame);
+            frame.contentWindow.removeEventListener('load', callback, false);
+
+            expect(removeEventListener).toHaveBeenCalledWith('load', callback, false);
+        });
+    });
+});
diff --git a/test/unit/utils.js b/test/unit/utils.js
index e050f5f..c0ac6cb 100644
--- a/test/unit/utils.js
+++ b/test/unit/utils.js
@@ -556,6 +556,7 @@
                 spyOn(utils, "location").andReturn({
                     href: "http://127.0.0.1/ripple/index.html",
                     protocol: "http:",
+                    port: "",
                     hostname: "127.0.0.1",
                     pathname: "/ripple/index.html"
                 });
@@ -566,16 +567,18 @@
                 spyOn(utils, "location").andReturn({
                     href: "http://127.0.0.1/ripple/",
                     protocol: "http:",
+                    port: "8080",
                     hostname: "127.0.0.1",
                     pathname: "/ripple/"
                 });
-                expect(utils.rippleLocation()).toBe("http://127.0.0.1/ripple/");
+                expect(utils.rippleLocation()).toBe("http://127.0.0.1:8080/ripple/");
             });
 
             it("returns the base path when no trailing forward slash exists", function () {
                 spyOn(utils, "location").andReturn({
                     href: "http://127.0.0.1/ripple",
                     protocol: "http:",
+                    port: "",
                     hostname: "127.0.0.1",
                     pathname: "/ripple"
                 });
@@ -586,10 +589,11 @@
                 spyOn(utils, "location").andReturn({
                     href: "http://127.0.0.1/i/will/put/ripple/here/",
                     protocol: "http:",
+                    port: "6767",
                     hostname: "127.0.0.1",
                     pathname: "/i/will/put/ripple/here/"
                 });
-                expect(utils.rippleLocation()).toBe("http://127.0.0.1/i/will/put/ripple/here/");
+                expect(utils.rippleLocation()).toBe("http://127.0.0.1:6767/i/will/put/ripple/here/");
             });
         });
 
diff --git a/test/unit/w3c/geolocation.js b/test/unit/w3c/geolocation.js
index 3e37a34..475de56 100644
--- a/test/unit/w3c/geolocation.js
+++ b/test/unit/w3c/geolocation.js
@@ -94,12 +94,16 @@
         });
 
         it("calls the success callback on the given interval", function () {
-            var watch = geolocation.watchPosition(success, error, {frequency: 10});
-            waits(39);
-            runs(function () {
-                expect(success.callCount).toBe(3);
-                geolocation.clearWatch(watch);
+            spyOn(window, "setInterval").andCallFake(function (callback, frequency) {
+                expect(frequency).toBe(10);
+                callback();
             });
+
+            var watch = geolocation.watchPosition(success, error, {frequency: 10});
+
+            expect(window.setInterval).toHaveBeenCalled();
+            expect(success).toHaveBeenCalled();
+            geolocation.clearWatch(watch);
         });
     });
 });
diff --git a/test/unit/webworks/fsCache.js b/test/unit/webworks/fsCache.js
index 14378af..324c1c5 100644
--- a/test/unit/webworks/fsCache.js
+++ b/test/unit/webworks/fsCache.js
@@ -76,17 +76,11 @@
             it("returns true when the file exists", function () {
                 spyOn(fs, "stat");
                 expect(cache.file.exists("/hungry.js")).toBe(true);
-                expect(fs.stat.argsForCall[0][0]).toBe("/hungry.js");
-                expect(typeof fs.stat.argsForCall[0][1]).toBe("function");
-                expect(typeof fs.stat.argsForCall[0][2]).toBe("function");
             });
 
             it("returns false when when given a directory", function () {
                 spyOn(fs, "stat");
                 expect(cache.file.exists("/dudeDir")).toBe(false);
-                expect(fs.stat.argsForCall[0][0]).toBe("/dudeDir");
-                expect(typeof fs.stat.argsForCall[0][1]).toBe("function");
-                expect(typeof fs.stat.argsForCall[0][2]).toBe("function");
             });
         });
 
@@ -177,36 +171,22 @@
             it("returns true when the directory exists", function () {
                 spyOn(fs, "stat");
                 expect(cache.dir.exists("/dudeDir")).toBe(true);
-                expect(fs.stat.argsForCall[0][0]).toBe("/dudeDir");
-                expect(typeof fs.stat.argsForCall[0][1]).toBe("function");
-                expect(typeof fs.stat.argsForCall[0][2]).toBe("function");
             });
 
             it("returns false when given a file", function () {
                 spyOn(fs, "stat");
                 expect(cache.dir.exists("/hungry.js")).toBe(false);
-                expect(fs.stat.argsForCall[0][0]).toBe("/hungry.js");
-                expect(typeof fs.stat.argsForCall[0][1]).toBe("function");
-                expect(typeof fs.stat.argsForCall[0][2]).toBe("function");
+            });
+
+            it("returns true when the directory exists", function () {
+                spyOn(fs, "stat");
+                expect(cache.dir.exists("/dudeDir")).toBe(true);
             });
         });
 
         describe("getParentDirectory", function () {
             it("returns the path to the parent directory", function () {
-                var entry = {
-                    getParent: jasmine.createSpy()
-                };
-
-                spyOn(fs, "stat").andCallFake(function (path, success, error) {
-                    success(entry);
-                });
-
                 expect(cache.dir.getParentDirectory("/dudeDir")).toBe("/");
-                expect(fs.stat.argsForCall[0][0]).toBe("/dudeDir");
-                expect(typeof fs.stat.argsForCall[0][1]).toBe("function");
-                expect(typeof fs.stat.argsForCall[0][2]).toBe("function");
-                expect(typeof entry.getParent.argsForCall[0][0]).toBe("function");
-                expect(typeof entry.getParent.argsForCall[0][1]).toBe("function");
             });
         });
 
diff --git a/test/unit/webworks/utils.js b/test/unit/webworks/utils.js
index e6fb6be..8067f29 100644
--- a/test/unit/webworks/utils.js
+++ b/test/unit/webworks/utils.js
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-var utils = require('ripple/platform/webworks.core/2.0.0/client/utils');
-
 describe("utils", function () {
+    var utils = require('ripple/platform/webworks.core/2.0.0/client/utils');
+
     beforeEach(function () {
         global.BlobBuilder = global.WebKitBlobBuilder = jasmine.createSpy();
     });
@@ -53,7 +53,7 @@
         it("can translate a blob into a string and back", function () {
             var blobBuilder = {
                     append: jasmine.createSpy(),
-                    getBlob: jasmine.createSpy().andReturn({})
+                    getBlob: jasmine.createSpy().andReturn({size: 3})
                 },
                 str = "da foo",
                 blob;
@@ -62,7 +62,8 @@
 
             blob = utils.stringToBlob(str);
 
-            expect(blob.uuid).toBeDefined();
+            expect(blob.id).toBeDefined();
+            expect(blob.length).toBeDefined();
             expect(utils.blobToString(blob)).toEqual(str);
             expect(utils.stringToBlob(str)).toEqual(blob);
             expect(blobBuilder.append).toHaveBeenCalledWith(str);
diff --git a/thirdparty/jasmine b/thirdparty/jasmine
index 6b59567..41f4960 160000
--- a/thirdparty/jasmine
+++ b/thirdparty/jasmine
@@ -1 +1 @@
-Subproject commit 6b5956724b7e64325c6465bc426bd924d6f2aefe
+Subproject commit 41f496001fd02da89081246865ba59c1430db9f1