You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by lo...@apache.org on 2013/05/20 19:44:15 UTC

[3/6] [CB-3367] Updates the framework to work with a smarter plugman and have a dumber packager - Re-writes cordova/plugin scripts to match the CLI interface - Includes the use of a global plugin repository for lookup - Adds a native/ folder for co

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/bin/test/cordova/unit/spec/lib/file-manager.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/test/cordova/unit/spec/lib/file-manager.js b/blackberry10/bin/test/cordova/unit/spec/lib/file-manager.js
index 68b60b8..1b1c6ff 100644
--- a/blackberry10/bin/test/cordova/unit/spec/lib/file-manager.js
+++ b/blackberry10/bin/test/cordova/unit/spec/lib/file-manager.js
@@ -23,104 +23,15 @@ var srcPath = __dirname + "/../../../../../templates/project/cordova/lib/",
 
 describe("File manager", function () {
 
+    beforeEach(function () {
+        wrench.mkdirSyncRecursive(testData.session.outputDir);
+    });
+
     afterEach(function () {
         //cleanup packager-tests temp folder
         wrench.rmdirSyncRecursive(testData.session.outputDir);
     });
 
-    it("prepareOutputFiles() should copy files and unzip archive", function () {
-        spyOn(wrench, "copyDirSyncRecursive");
-        fileMgr.prepareOutputFiles(session);
-
-        expect(fs.existsSync(session.sourcePaths.CHROME)).toBeTruthy();
-        expect(wrench.copyDirSyncRecursive).toHaveBeenCalledWith(session.conf.DEPENDENCIES_BOOTSTRAP, session.sourcePaths.CHROME);
-        expect(fs.existsSync(session.sourcePaths.LIB)).toBeTruthy();
-    });
-
-
-    it("copyWWE() should copy wwe of the specified target", function () {
-        //Create packager-tests source folder
-        wrench.mkdirSyncRecursive(session.sourceDir);
-
-        spyOn(packager_utils, "copyFile");
-        fileMgr.copyWWE(session, "simulator");
-
-        expect(packager_utils.copyFile).toHaveBeenCalledWith(path.normalize(session.conf.DEPENDENCIES_BOOTSTRAP + "/wwe"), path.normalize(session.sourceDir));
-    });
-/* TODO: this test needs to be re-written
-    it("copyExtensions() should copy all .js files required by features listed in config.xml", function () {
-        var session = testData.session,
-            featureId = "Device",
-            toDir = path.join(session.sourcePaths.EXT, featureId),
-            apiDir = path.resolve(session.conf.EXT, featureId),
-
-            //extension javascript files
-            indexJS = path.join(apiDir, "index.js"),
-            clientJS = path.join(apiDir, "client.js"),
-            subfolderJS = path.join(apiDir, "/subfolder/myjs.js");//Sub folder js file
-
-        //Create packager-tests source folder
-        wrench.mkdirSyncRecursive(session.sourceDir);
-
-        spyOn(fs, "existsSync").andReturn(true);
-        spyOn(wrench, "mkdirSyncRecursive");
-        spyOn(packager_utils, "copyFile");
-
-        //Mock the extension directory
-        spyOn(wrench, "readdirSyncRecursive").andCallFake(function (directory) {
-            return [
-                indexJS,
-                clientJS,
-                subfolderJS,
-            ];
-        });
-
-        fileMgr.copyExtensions(session, session.targets[0]);
-
-        //Extension directory is created
-        expect(wrench.mkdirSyncRecursive).toHaveBeenCalledWith(toDir, "0755");
-
-        //Javascript files are copied
-        expect(packager_utils.copyFile).toHaveBeenCalledWith(indexJS, toDir, apiDir);
-        expect(packager_utils.copyFile).toHaveBeenCalledWith(clientJS, toDir, apiDir);
-        expect(packager_utils.copyFile).toHaveBeenCalledWith(subfolderJS, toDir, apiDir);
-    });
-*/
-    it("copyExtensions() should copy .so files required by features listed in config.xml", function () {
-        var session = testData.session,
-            extBasename = "app",
-            apiDir = path.resolve(session.conf.EXT, extBasename),
-            soDest = session.sourcePaths.JNEXT_PLUGINS,
-
-            //extension .so files
-            simulatorSO = path.join(apiDir, "/simulator/myso.so"),//simulator so file
-            deviceSO = path.join(apiDir, "/device/myso.so");//device so file
-
-        //Create packager-tests source folder
-        wrench.mkdirSyncRecursive(session.sourceDir);
-
-        spyOn(fs, "existsSync").andReturn(true);
-        spyOn(wrench, "mkdirSyncRecursive");
-        spyOn(packager_utils, "copyFile");
-
-        //Mock the extension directory
-        spyOn(wrench, "readdirSyncRecursive").andCallFake(function (directory) {
-            return [
-                simulatorSO,
-                deviceSO
-            ];
-        });
-
-        fileMgr.copyExtensions(session, session.targets[0]);
-
-        //plugins/jnext output directory is created
-        expect(wrench.mkdirSyncRecursive).toHaveBeenCalledWith(session.sourcePaths.JNEXT_PLUGINS, "0755");
-
-        //The .so files are copied
-        expect(packager_utils.copyFile).toHaveBeenCalledWith(simulatorSO, soDest);
-        expect(packager_utils.copyFile).toHaveBeenCalledWith(deviceSO, soDest);
-    });
-
     it("unzip() should extract 'from' zip file to 'to' directory", function () {
         var from = session.archivePath,
             to = session.sourceDir;
@@ -144,28 +55,6 @@ describe("File manager", function () {
         expect(fs.existsSync(session.sourceDir)).toBeFalsy();
     });
 
-    it("prepareOutputFiles() should copy files if a folder is sent in", function () {
-        spyOn(wrench, "copyDirSyncRecursive");
-        fileMgr.prepareOutputFiles(session);
-
-        expect(fs.existsSync(session.sourcePaths.CHROME)).toBeTruthy();
-        expect(wrench.copyDirSyncRecursive).toHaveBeenCalledWith(session.conf.DEPENDENCIES_BOOTSTRAP, session.sourcePaths.CHROME);
-        expect(fs.existsSync(session.sourcePaths.LIB)).toBeTruthy();
-    });
-
-    it("prepareOutputFiles() should copy files if a folder is sent in without .bbwpignore", function () {
-        var oldPathExistsSync = fs.existsSync;
-        spyOn(fs, "existsSync").andCallFake(function (ipath) {
-            return path.basename(ipath) === conf.BBWP_IGNORE_FILENAME ? false : oldPathExistsSync(ipath);
-        });
-        spyOn(wrench, "copyDirSyncRecursive");
-        fileMgr.prepareOutputFiles(session);
-
-        expect(fs.existsSync(session.sourcePaths.CHROME)).toBeTruthy();
-        expect(wrench.copyDirSyncRecursive).toHaveBeenCalledWith(session.conf.DEPENDENCIES_BOOTSTRAP, session.sourcePaths.CHROME);
-        expect(fs.existsSync(session.sourcePaths.LIB)).toBeTruthy();
-    });
-
     it("prepareOutputFiles() should throw an error if the archive path doesn't exist", function () {
         spyOn(wrench, "copyDirSyncRecursive");
         var tempSession = testUtilities.cloneObj(session);

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/bin/test/plugins/Accelerometer/index.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/test/plugins/Accelerometer/index.js b/blackberry10/bin/test/plugins/Accelerometer/index.js
index e907d56..1819ba7 100644
--- a/blackberry10/bin/test/plugins/Accelerometer/index.js
+++ b/blackberry10/bin/test/plugins/Accelerometer/index.js
@@ -14,7 +14,7 @@
 * limitations under the License.
 */
 describe("Accelerometer", function () {
-    var _apiDir = __dirname + "./../../../templates/project/plugins/Accelerometer/src/blackberry10/",
+    var _apiDir = __dirname + "./../../../../plugins/Accelerometer/src/blackberry10/",
         index,
         callback,
         result = {

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/bin/test/plugins/Battery/index.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/test/plugins/Battery/index.js b/blackberry10/bin/test/plugins/Battery/index.js
index 9343890..ff82a21 100644
--- a/blackberry10/bin/test/plugins/Battery/index.js
+++ b/blackberry10/bin/test/plugins/Battery/index.js
@@ -16,7 +16,7 @@
 
 describe("Battery", function () {
 
-    var _apiDir = __dirname + "./../../../templates/project/plugins/Battery/src/blackberry10/",
+    var _apiDir = __dirname + "./../../../../plugins/Battery/src/blackberry10/",
         index,
         callback,
         mockPluginResult = {

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/bin/test/plugins/Camera/index.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/test/plugins/Camera/index.js b/blackberry10/bin/test/plugins/Camera/index.js
index d498a56..3dcee33 100644
--- a/blackberry10/bin/test/plugins/Camera/index.js
+++ b/blackberry10/bin/test/plugins/Camera/index.js
@@ -14,7 +14,7 @@
 * limitations under the License.
 */
 describe("Camera", function () {
-    var _apiDir = __dirname + "./../../../templates/project/plugins/Camera/src/blackberry10/",
+    var _apiDir = __dirname + "./../../../../plugins/Camera/src/blackberry10/",
         index,
         mockDone,
         mockCancel,

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/bin/test/plugins/Device/index.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/test/plugins/Device/index.js b/blackberry10/bin/test/plugins/Device/index.js
index d6b6d47..4c5fb29 100644
--- a/blackberry10/bin/test/plugins/Device/index.js
+++ b/blackberry10/bin/test/plugins/Device/index.js
@@ -16,7 +16,7 @@
 
 describe("Device", function () {
 
-    var _apiDir = __dirname + "./../../../templates/project/plugins/Device/src/blackberry10/",
+    var _apiDir = __dirname + "./../../../../plugins/Device/src/blackberry10/",
         index,
         result = {
             ok: jasmine.createSpy()

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/bin/test/plugins/Logger/index.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/test/plugins/Logger/index.js b/blackberry10/bin/test/plugins/Logger/index.js
index 4cd0dca..cec4556 100644
--- a/blackberry10/bin/test/plugins/Logger/index.js
+++ b/blackberry10/bin/test/plugins/Logger/index.js
@@ -16,7 +16,7 @@
 
 describe("Logger", function () {
 
-    var _apiDir = __dirname + "./../../../templates/project/plugins/Logger/src/blackberry10/",
+    var _apiDir = __dirname + "./../../../../plugins/Logger/src/blackberry10/",
         index,
         result = {
             noResult: jasmine.createSpy("noResult")

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/bin/test/plugins/NetworkStatus/index.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/test/plugins/NetworkStatus/index.js b/blackberry10/bin/test/plugins/NetworkStatus/index.js
index 9aa270d..ac87390 100644
--- a/blackberry10/bin/test/plugins/NetworkStatus/index.js
+++ b/blackberry10/bin/test/plugins/NetworkStatus/index.js
@@ -16,7 +16,7 @@
 
 
 describe("NetworkStatus", function () {
-    var _apiDir = __dirname + "./../../../templates/project/plugins/NetworkStatus/src/blackberry10/",
+    var _apiDir = __dirname + "./../../../../plugins/NetworkStatus/src/blackberry10/",
         index,
         result = {
             ok: jasmine.createSpy(),

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/bin/test/plugins/Notification/index.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/test/plugins/Notification/index.js b/blackberry10/bin/test/plugins/Notification/index.js
index a8f680f..8d10e25 100644
--- a/blackberry10/bin/test/plugins/Notification/index.js
+++ b/blackberry10/bin/test/plugins/Notification/index.js
@@ -38,7 +38,7 @@ function mockAndTestDialog(htmlmessage, title, dialogType, buttonLabel) {
 }
 
 describe("Notification", function () {
-    var _apiDir = __dirname + "./../../../templates/project/plugins/Notification/src/blackberry10/",
+    var _apiDir = __dirname + "./../../../../plugins/Notification/src/blackberry10/",
     index,
     success = function() {},
     fail = function() {},

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/bin/test/plugins/SplashScreen/index.js
----------------------------------------------------------------------
diff --git a/blackberry10/bin/test/plugins/SplashScreen/index.js b/blackberry10/bin/test/plugins/SplashScreen/index.js
index ef010df..658ce3d 100644
--- a/blackberry10/bin/test/plugins/SplashScreen/index.js
+++ b/blackberry10/bin/test/plugins/SplashScreen/index.js
@@ -14,7 +14,7 @@
 * limitations under the License.
 */
 describe("SplashScreen", function () {
-    var _apiDir = __dirname + "./../../../templates/project/plugins/SplashScreen/src/blackberry10/",
+    var _apiDir = __dirname + "./../../../../plugins/SplashScreen/src/blackberry10/",
         index,
         mockedEnv = {
             response: {

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/framework/bootstrap/wwe
----------------------------------------------------------------------
diff --git a/blackberry10/framework/bootstrap/wwe b/blackberry10/framework/bootstrap/wwe
deleted file mode 100644
index 0e48b92..0000000
--- a/blackberry10/framework/bootstrap/wwe
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-exec weblauncher "$@"
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/package.json
----------------------------------------------------------------------
diff --git a/blackberry10/package.json b/blackberry10/package.json
index 227df34..95b9b35 100644
--- a/blackberry10/package.json
+++ b/blackberry10/package.json
@@ -1,11 +1,11 @@
 {
-  "name": "cordova-blackberry10",
+  "name": "cordova-blackberry",
   "version": "0.0.1",
-  "description": "cordova-blackberry10",
-  "repository": "git://github.rim.net/webworks/cordova-blackberry10.git",
+  "description": "cordova-blackberry",
+  "repository": "https://git-wip-us.apache.org/repos/asf?p=cordova-blackberry.git",
   "author": {
-    "name": "Research In Motion",
-    "url": "http://github.rim.net/webworks/cordova-blackberry10.git"
+    "name": "BlackBerry",
+    "url": "http://developer.blackberry.com/html5/"
   },
   "licenses": [{
     "type": "Apache 2.0",
@@ -23,7 +23,9 @@
     "xml2js": "0.1.13",
     "validator": "0.4.1",
     "wrench": "1.3.9",
-    "plugman": "git+https://github.com/blackberry/cordova-plugman.git#blackberry10"
+    "shelljs":"0.1.2",
+    "elementtree": "0.1.x",
+    "plugman": "git+https://github.com/apache/cordova-plugman.git"
   },
   "devDependencies": {
     "jake":"*"

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Accelerometer/plugin.xml
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Accelerometer/plugin.xml b/blackberry10/plugins/Accelerometer/plugin.xml
new file mode 100644
index 0000000..0c8d3dd
--- /dev/null
+++ b/blackberry10/plugins/Accelerometer/plugin.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+
+-->
+
+<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
+    id="org.apache.cordova.core.Accelerometer"
+    version="0.0.1">
+
+    <name>Device Motion</name>
+
+    <platform name="blackberry10">
+        <config-file target="www/config.xml" parent="/widget">
+            <feature name="Accelerometer" value="Accelerometer"/>
+        </config-file>
+        <source-file src="src/blackberry10/index.js" target-dir="Accelerometer" />
+    </platform>
+</plugin>

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Accelerometer/src/blackberry10/index.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Accelerometer/src/blackberry10/index.js b/blackberry10/plugins/Accelerometer/src/blackberry10/index.js
new file mode 100644
index 0000000..47abe42
--- /dev/null
+++ b/blackberry10/plugins/Accelerometer/src/blackberry10/index.js
@@ -0,0 +1,45 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+var callback;
+
+module.exports = {
+    start: function (success, fail, args, env) {
+        var result = new PluginResult(args, env);
+        window.removeEventListener("devicemotion", callback);
+        callback = function (motion) {
+            var info = {
+                x: motion.accelerationIncludingGravity.x,
+                y: motion.accelerationIncludingGravity.y,
+                z: motion.accelerationIncludingGravity.z,
+                timestamp: motion.timestamp
+            };
+            result.callbackOk(info, true);
+        };
+        window.addEventListener("devicemotion", callback);
+        result.noResult(true);
+    },
+    stop: function (success, fail, args, env) {
+        var result = new PluginResult(args, env);
+        window.removeEventListener("devicemotion", callback);
+        result.ok("removed");
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Battery/plugin.xml
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Battery/plugin.xml b/blackberry10/plugins/Battery/plugin.xml
new file mode 100644
index 0000000..58b6356
--- /dev/null
+++ b/blackberry10/plugins/Battery/plugin.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+
+-->
+
+<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
+    id="org.apache.cordova.core.Battery"
+    version="0.0.1">
+
+    <name>Battery</name>
+
+    <platform name="blackberry10">
+        <source-file src="src/blackberry10/index.js" target-dir="Battery" />
+        <config-file target="www/config.xml" parent="/widget">
+            <feature name="Battery" value="Battery"/>
+        </config-file>
+    </platform>
+</plugin>

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Battery/src/blackberry10/index.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Battery/src/blackberry10/index.js b/blackberry10/plugins/Battery/src/blackberry10/index.js
new file mode 100644
index 0000000..07a943c
--- /dev/null
+++ b/blackberry10/plugins/Battery/src/blackberry10/index.js
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2010-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 SYSTEM_EVENTS = ["device.battery.statusChange",
+                     "device.battery.chargeLow",
+                     "device.battery.chargeCritical"],
+    device = window.qnx.webplatform.device,
+    _clientListeners = {};
+
+module.exports = {
+    start: function (success, fail, args, env) {
+        var result = new PluginResult(args, env),
+            listener = function (info) {
+                result.callbackOk(info, true);
+            };
+
+        if (_clientListeners[env.webview.id]) {
+            //TODO: Change back to erroring out after reset is implemented
+            //result.error("Battery listener already running");
+            SYSTEM_EVENTS.forEach(function (event) {
+                device.removeEventListener(event, _clientListeners[env.webview.id]);
+            });
+        }
+
+        _clientListeners[env.webview.id] = listener;
+        SYSTEM_EVENTS.forEach(function (event) {
+            device.addEventListener(event, listener);
+        });
+        result.noResult(true);
+    },
+    stop: function (success, fail, args, env) {
+        var result = new PluginResult(args, env),
+            listener = _clientListeners[env.webview.id];
+
+        if (!listener) {
+            result.error("Battery listener has not started");
+        } else {
+            SYSTEM_EVENTS.forEach(function (event) {
+                device.removeEventListener(event, listener);
+            });
+            delete _clientListeners[env.webview.id];
+            result.noResult(false);
+        }
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Camera/plugin.xml
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Camera/plugin.xml b/blackberry10/plugins/Camera/plugin.xml
new file mode 100644
index 0000000..4fe8693
--- /dev/null
+++ b/blackberry10/plugins/Camera/plugin.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+
+-->
+
+<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
+    id="org.apache.cordova.core.Camera"
+    version="0.0.1">
+
+    <name>Camera</name>
+
+    <platform name="blackberry10">
+        <source-file src="src/blackberry10/index.js" target-dir="Camera" />
+        <config-file target="www/config.xml" parent="/widget">
+            <feature name="Camera" value="Camera"/>
+        </config-file>
+    </platform>
+</plugin>

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Camera/src/blackberry10/index.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Camera/src/blackberry10/index.js b/blackberry10/plugins/Camera/src/blackberry10/index.js
new file mode 100644
index 0000000..922f049
--- /dev/null
+++ b/blackberry10/plugins/Camera/src/blackberry10/index.js
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2010-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 PictureSourceType = {
+        PHOTOLIBRARY : 0,    // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
+        CAMERA : 1,          // Take picture from camera
+        SAVEDPHOTOALBUM : 2  // Choose image from picture library (same as PHOTOLIBRARY for Android)
+    },
+    DestinationType = {
+        DATA_URL: 0,         // Return base64 encoded string
+        FILE_URI: 1,         // Return file uri (content://media/external/images/media/2 for Android)
+        NATIVE_URI: 2        // Return native uri (eg. asset-library://... for iOS)
+    };
+
+function encodeBase64(filePath, callback) {
+    var sandbox = window.qnx.webplatform.getController().setFileSystemSandbox, // save original sandbox value
+        errorHandler = function (err) {
+            var msg = "An error occured: ";
+
+            switch (err.code) {
+            case FileError.NOT_FOUND_ERR:
+                msg += "File or directory not found";
+                break;
+
+            case FileError.NOT_READABLE_ERR:
+                msg += "File or directory not readable";
+                break;
+
+            case FileError.PATH_EXISTS_ERR:
+                msg += "File or directory already exists";
+                break;
+
+            case FileError.TYPE_MISMATCH_ERR:
+                msg += "Invalid file type";
+                break;
+
+            default:
+                msg += "Unknown Error";
+                break;
+            };
+
+            // set it back to original value
+            window.qnx.webplatform.getController().setFileSystemSandbox = sandbox;
+            callback(msg);
+        },
+        gotFile = function (fileEntry) {
+            fileEntry.file(function (file) {
+                var reader = new FileReader();
+
+                reader.onloadend = function (e) {
+                    // set it back to original value
+                    window.qnx.webplatform.getController().setFileSystemSandbox = sandbox;
+                    callback(this.result);
+                };
+
+                reader.readAsDataURL(file);
+            }, errorHandler);
+        },
+        onInitFs = function (fs) {
+            window.qnx.webplatform.getController().setFileSystemSandbox = false;
+            fs.root.getFile(filePath, {create: false}, gotFile, errorHandler);
+        };
+
+    window.webkitRequestFileSystem(window.TEMPORARY, 10 * 1024 * 1024, onInitFs, errorHandler); // set size to 10MB max
+}
+
+module.exports = {
+    takePicture: function (success, fail, args, env) {
+        var destinationType = JSON.parse(decodeURIComponent(args[1])),
+            sourceType = JSON.parse(decodeURIComponent(args[2])),
+            result = new PluginResult(args, env),
+            done = function (data) {
+                if (destinationType === DestinationType.FILE_URI) {
+                    data = "file://" + data;
+                    result.callbackOk(data, false);
+                } else {
+                    encodeBase64(data, function (data) {
+                        if (/^data:/.test(data)) {
+                            data = data.slice(data.indexOf(",") + 1);
+                            result.callbackOk(data, false);
+                        } else {
+                            result.callbackError(data, false);
+                        }
+                    });
+                }
+            },
+            cancel = function (reason) {
+                result.callbackError(reason, false);
+            },
+            invoked = function (error) {
+                if (error) {
+                    result.callbackError(error, false);
+                }
+            };
+
+        switch(sourceType) {
+        case PictureSourceType.CAMERA:
+            window.qnx.webplatform.getApplication().cards.camera.open("photo", done, cancel, invoked);
+            break;
+
+        case PictureSourceType.PHOTOLIBRARY:
+        case PictureSourceType.SAVEDPHOTOALBUM:
+            window.qnx.webplatform.getApplication().cards.filePicker.open({
+                mode: "Picker",
+                type: ["picture"]
+            }, done, cancel, invoked);
+            break;
+        }
+
+        result.noResult(true);
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Contacts/plugin.xml
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Contacts/plugin.xml b/blackberry10/plugins/Contacts/plugin.xml
new file mode 100644
index 0000000..4255297
--- /dev/null
+++ b/blackberry10/plugins/Contacts/plugin.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+
+-->
+
+<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
+    id="org.apache.cordova.core.Contacts"
+    version="0.0.1">
+
+    <name>Contacts</name>
+
+    <platform name="blackberry10">
+        <config-file target="www/config.xml" parent="/widget">
+            <feature name="Contacts" value="Contacts"/>
+        </config-file>
+      </platform>
+</plugin>

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Contacts/src/blackberry10/ContactActivity.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Contacts/src/blackberry10/ContactActivity.js b/blackberry10/plugins/Contacts/src/blackberry10/ContactActivity.js
new file mode 100644
index 0000000..0794d23
--- /dev/null
+++ b/blackberry10/plugins/Contacts/src/blackberry10/ContactActivity.js
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2012 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 ContactActivity = function (args) {
+    this.direction = args.direction || null;
+    this.description = args.description || "";
+    this.mimeType = args.mimeType || "";
+    this.timestamp = new Date(parseInt(args.timestamp, 10)) || null;
+};
+
+Object.defineProperty(ContactActivity, "INCOMING", {"value": true});
+Object.defineProperty(ContactActivity, "OUTGOING", {"value": false});
+
+module.exports = ContactActivity;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Contacts/src/blackberry10/ContactAddress.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Contacts/src/blackberry10/ContactAddress.js b/blackberry10/plugins/Contacts/src/blackberry10/ContactAddress.js
new file mode 100644
index 0000000..1ba9fe4
--- /dev/null
+++ b/blackberry10/plugins/Contacts/src/blackberry10/ContactAddress.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2012 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 ContactAddress = function (properties) {
+    this.type = properties && properties.type ? properties.type : "";
+    this.streetAddress = properties && properties.streetAddress ? properties.streetAddress : "";
+    this.streetOther = properties && properties.streetOther ? properties.streetOther : "";
+    this.locality = properties && properties.locality ? properties.locality : "";
+    this.region = properties && properties.region ? properties.region : "";
+    this.postalCode = properties && properties.postalCode ? properties.postalCode : "";
+    this.country = properties && properties.country ? properties.country : "";
+};
+
+Object.defineProperty(ContactAddress, "HOME", {"value": "home"});
+Object.defineProperty(ContactAddress, "WORK", {"value": "work"});
+Object.defineProperty(ContactAddress, "OTHER", {"value": "other"});
+
+module.exports = ContactAddress;

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Contacts/src/blackberry10/ContactError.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Contacts/src/blackberry10/ContactError.js b/blackberry10/plugins/Contacts/src/blackberry10/ContactError.js
new file mode 100644
index 0000000..f20f85e
--- /dev/null
+++ b/blackberry10/plugins/Contacts/src/blackberry10/ContactError.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2012 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 ContactError = function (code, msg) {
+    this.code = code;
+    this.message = msg;
+};
+
+Object.defineProperty(ContactError, "UNKNOWN_ERROR", { "value": 0 });
+Object.defineProperty(ContactError, "INVALID_ARGUMENT_ERROR", { "value": 1 });
+Object.defineProperty(ContactError, "TIMEOUT_ERROR", { "value": 2 });
+Object.defineProperty(ContactError, "PENDING_OPERATION_ERROR", { "value": 3 });
+Object.defineProperty(ContactError, "IO_ERROR", { "value": 4 });
+Object.defineProperty(ContactError, "NOT_SUPPORTED_ERROR", { "value": 5 });
+Object.defineProperty(ContactError, "PERMISSION_DENIED_ERROR", { "value": 20 });
+
+module.exports = ContactError;
+

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Contacts/src/blackberry10/ContactField.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Contacts/src/blackberry10/ContactField.js b/blackberry10/plugins/Contacts/src/blackberry10/ContactField.js
new file mode 100644
index 0000000..aad735c
--- /dev/null
+++ b/blackberry10/plugins/Contacts/src/blackberry10/ContactField.js
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2012 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 ContactField = function (type, value) {
+    this.type = type || "";
+    this.value = value || "";
+};
+
+Object.defineProperty(ContactField, "HOME", {"value": "home"});
+Object.defineProperty(ContactField, "WORK", {"value": "work"});
+Object.defineProperty(ContactField, "OTHER", {"value": "other"});
+Object.defineProperty(ContactField, "MOBILE", {"value": "mobile"});
+Object.defineProperty(ContactField, "DIRECT", {"value": "direct"});
+
+module.exports = ContactField;

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Contacts/src/blackberry10/ContactFindOptions.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Contacts/src/blackberry10/ContactFindOptions.js b/blackberry10/plugins/Contacts/src/blackberry10/ContactFindOptions.js
new file mode 100644
index 0000000..8be830d
--- /dev/null
+++ b/blackberry10/plugins/Contacts/src/blackberry10/ContactFindOptions.js
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2012 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.
+ */
+
+/**
+ * ContactFindOptions.
+ * @constructor
+ * @param filter search fields
+ * @param sort sort fields and order
+ * @param limit max number of contacts to return
+ * @param favorite if set, only favorite contacts will be returned
+ */
+
+var ContactFindOptions = function (filter, sort, limit, favorite) {
+    this.filter = filter || null;
+    this.sort = sort || null;
+    this.limit = limit || -1; // -1 for returning all results
+    this.favorite = favorite || false;
+    this.includeAccounts = [];
+    this.excludeAccounts = [];
+};
+
+Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_GIVEN_NAME", { "value": 0 });
+Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_FAMILY_NAME", { "value": 1 });
+Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_ORGANIZATION_NAME", { "value": 2 });
+Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_PHONE", { "value": 3 });
+Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_EMAIL", { "value": 4 });
+Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_BBMPIN", { "value": 5 });
+Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_LINKEDIN", { "value": 6 });
+Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_TWITTER", { "value": 7 });
+Object.defineProperty(ContactFindOptions, "SEARCH_FIELD_VIDEO_CHAT", { "value": 8 });
+
+Object.defineProperty(ContactFindOptions, "SORT_FIELD_GIVEN_NAME", { "value": 0 });
+Object.defineProperty(ContactFindOptions, "SORT_FIELD_FAMILY_NAME", { "value": 1 });
+Object.defineProperty(ContactFindOptions, "SORT_FIELD_ORGANIZATION_NAME", { "value": 2 });
+
+module.exports = ContactFindOptions;
+

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Contacts/src/blackberry10/ContactName.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Contacts/src/blackberry10/ContactName.js b/blackberry10/plugins/Contacts/src/blackberry10/ContactName.js
new file mode 100644
index 0000000..9b74753
--- /dev/null
+++ b/blackberry10/plugins/Contacts/src/blackberry10/ContactName.js
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012 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.
+ */
+
+function toFormattedName(properties) {
+    var formatted = "";
+    if (properties && properties.givenName) {
+        formatted = properties.givenName;
+        if (properties && properties.familyName) {
+            formatted += " " + properties.familyName;
+        }
+    }
+    return formatted;
+}
+
+var ContactName = function (properties) {
+    this.familyName = properties && properties.familyName ? properties.familyName : "";
+    this.givenName = properties && properties.givenName ? properties.givenName : "";
+    this.formatted = toFormattedName(properties);
+    this.middleName = properties && properties.middleName ? properties.middleName : "";
+    this.honorificPrefix = properties && properties.honorificPrefix ? properties.honorificPrefix : "";
+    this.honorificSuffix = properties && properties.honorificSuffix ? properties.honorificSuffix : "";
+    this.phoneticFamilyName = properties && properties.phoneticFamilyName ? properties.phoneticFamilyName : "";
+    this.phoneticGivenName = properties && properties.phoneticGivenName ? properties.phoneticGivenName : "";
+};
+
+module.exports = ContactName;

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Contacts/src/blackberry10/ContactNews.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Contacts/src/blackberry10/ContactNews.js b/blackberry10/plugins/Contacts/src/blackberry10/ContactNews.js
new file mode 100644
index 0000000..7aa9d8c
--- /dev/null
+++ b/blackberry10/plugins/Contacts/src/blackberry10/ContactNews.js
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2012 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 ContactNews = function (args) {
+    this.title = args.title || "";
+    this.body = args.body || "";
+    this.articleSource = args.articleSource || "";
+    this.companies = args.companies || [];
+    this.publishedAt = new Date(parseInt(args.publishedAt, 10)) || null;
+    this.uri = args.uri || "";
+    this.type = args.type || "";
+};
+
+module.exports = ContactNews;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Contacts/src/blackberry10/ContactOrganization.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Contacts/src/blackberry10/ContactOrganization.js b/blackberry10/plugins/Contacts/src/blackberry10/ContactOrganization.js
new file mode 100644
index 0000000..ecf5d0c
--- /dev/null
+++ b/blackberry10/plugins/Contacts/src/blackberry10/ContactOrganization.js
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2012 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 ContactOrganization = function (properties) {
+    this.name = properties && properties.name ? properties.name : "";
+    this.department = properties && properties.department ? properties.department : "";
+    this.title = properties && properties.title ? properties.title : "";
+};
+
+module.exports = ContactOrganization;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Contacts/src/blackberry10/ContactPhoto.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Contacts/src/blackberry10/ContactPhoto.js b/blackberry10/plugins/Contacts/src/blackberry10/ContactPhoto.js
new file mode 100644
index 0000000..5b1c9d6
--- /dev/null
+++ b/blackberry10/plugins/Contacts/src/blackberry10/ContactPhoto.js
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2012 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 ContactPhoto = function (originalFilePath, pref) {
+    this.originalFilePath = originalFilePath || "";
+    this.pref = pref || false;
+    this.largeFilePath = "";
+    this.smallFilePath = "";
+};
+
+module.exports = ContactPhoto;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Contacts/src/blackberry10/contactConsts.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Contacts/src/blackberry10/contactConsts.js b/blackberry10/plugins/Contacts/src/blackberry10/contactConsts.js
new file mode 100644
index 0000000..ef25206
--- /dev/null
+++ b/blackberry10/plugins/Contacts/src/blackberry10/contactConsts.js
@@ -0,0 +1,225 @@
+/*
+* Copyright 2012 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 ATTRIBUTE_KIND,
+    ATTRIBUTE_SUBKIND,
+    kindAttributeMap = {},
+    subKindAttributeMap = {},
+    _TITLE = 26,
+    _START_DATE = 43,
+    _END_DATE = 44;
+
+function populateKindAttributeMap() {
+    ATTRIBUTE_KIND = {
+        Invalid: 0,
+        Phone: 1,
+        Fax: 2,
+        Pager: 3,
+        Email: 4,
+        Website: 5,
+        Feed: 6,
+        Profile: 7,
+        Family: 8,
+        Person: 9,
+        Date: 10,
+        Group: 11,
+        Name: 12,
+        StockSymbol: 13,
+        Ranking: 14,
+        OrganizationAffiliation: 15,
+        Education: 16,
+        Note: 17,
+        InstantMessaging: 18,
+        VideoChat: 19,
+        ConnectionCount: 20,
+        Hidden: 21,
+        Biography: 22,
+        Sound: 23,
+        Notification: 24,
+        MessageSound: 25,
+        MessageNotification: 26
+    };
+
+    kindAttributeMap[ATTRIBUTE_KIND.Phone] = "phoneNumbers";
+    kindAttributeMap[ATTRIBUTE_KIND.Fax] = "faxNumbers";
+    kindAttributeMap[ATTRIBUTE_KIND.Pager] = "pagerNumber";
+    kindAttributeMap[ATTRIBUTE_KIND.Email] = "emails";
+    kindAttributeMap[ATTRIBUTE_KIND.Website] = "urls";
+    kindAttributeMap[ATTRIBUTE_KIND.Profile] = "socialNetworks";
+    kindAttributeMap[ATTRIBUTE_KIND.OrganizationAffiliation] = "organizations";
+    kindAttributeMap[ATTRIBUTE_KIND.Education] = "education";
+    kindAttributeMap[ATTRIBUTE_KIND.Note] = "note";
+    kindAttributeMap[ATTRIBUTE_KIND.InstantMessaging] = "ims";
+    kindAttributeMap[ATTRIBUTE_KIND.VideoChat] = "videoChat";
+    kindAttributeMap[ATTRIBUTE_KIND.Sound] = "ringtone";
+}
+
+function populateSubKindAttributeMap() {
+    ATTRIBUTE_SUBKIND = {
+        Invalid: 0,
+        Other: 1,
+        Home: 2,
+        Work: 3,
+        PhoneMobile: 4,
+        FaxDirect: 5,
+        Blog: 6,
+        WebsiteResume: 7,
+        WebsitePortfolio: 8,
+        WebsitePersonal: 9,
+        WebsiteCompany: 10,
+        ProfileFacebook: 11,
+        ProfileTwitter: 12,
+        ProfileLinkedIn: 13,
+        ProfileGist: 14,
+        ProfileTungle: 15,
+        FamilySpouse: 16,
+        FamilyChild: 17,
+        FamilyParent: 18,
+        PersonManager: 19,
+        PersonAssistant: 20,
+        DateBirthday: 21,
+        DateAnniversary: 22,
+        GroupDepartment: 23,
+        NameGiven: 24,
+        NameSurname: 25,
+        Title: _TITLE,
+        NameSuffix: 27,
+        NameMiddle: 28,
+        NameNickname: 29,
+        NameAlias: 30,
+        NameDisplayName: 31,
+        NamePhoneticGiven: 32,
+        NamePhoneticSurname: 33,
+        StockSymbolNyse: 34,
+        StockSymbolNasdaq: 35,
+        StockSymbolTse: 36,
+        StockSymbolLse: 37,
+        StockSymbolTsx: 38,
+        RankingKlout: 39,
+        RankingTrstRank: 40,
+        OrganizationAffiliationName: 41,
+        OrganizationAffiliationPhoneticName: 42,
+        OrganizationAffiliationTitle: _TITLE,
+        StartDate: _START_DATE,
+        EndDate: _END_DATE,
+        OrganizationAffiliationDetails: 45,
+        EducationInstitutionName: 46,
+        EducationStartDate: _START_DATE,
+        EducationEndDate: _END_DATE,
+        EducationDegree: 47,
+        EducationConcentration: 48,
+        EducationActivities: 49,
+        EducationNotes: 50,
+        InstantMessagingBbmPin: 51,
+        InstantMessagingAim: 52,
+        InstantMessagingAliwangwang: 53,
+        InstantMessagingGoogleTalk: 54,
+        InstantMessagingSametime: 55,
+        InstantMessagingIcq: 56,
+        InstantMessagingIrc: 57,
+        InstantMessagingJabber: 58,
+        InstantMessagingMsLcs: 59,
+        InstantMessagingMsn: 60,
+        InstantMessagingQq: 61,
+        InstantMessagingSkype: 62,
+        InstantMessagingYahooMessenger: 63,
+        InstantMessagingYahooMessengerJapan: 64,
+        VideoChatBbPlaybook: 65,
+        HiddenLinkedIn: 66,
+        HiddenFacebook: 67,
+        HiddenTwitter: 68,
+        ConnectionCountLinkedIn: 69,
+        ConnectionCountFacebook: 70,
+        ConnectionCountTwitter: 71,
+        HiddenChecksum: 72,
+        HiddenSpeedDial: 73,
+        BiographyFacebook: 74,
+        BiographyTwitter: 75,
+        BiographyLinkedIn: 76,
+        SoundRingtone: 77,
+        SimContactType: 78,
+        EcoID: 79,
+        Personal: 80,
+        StockSymbolAll: 81,
+        NotificationVibration: 82,
+        NotificationLED: 83,
+        MessageNotificationVibration: 84,
+        MessageNotificationLED: 85,
+        MessageNotificationDuringCall: 86,
+        VideoChatPin: 87
+    };
+
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.Other] = "other";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.Home] = "home";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.Work] = "work";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.PhoneMobile] = "mobile";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.FaxDirect] = "direct";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.Blog] = "blog";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.WebsiteResume] = "resume";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.WebsitePortfolio] = "portfolio";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.WebsitePersonal] = "personal";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.WebsiteCompany] = "company";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.ProfileFacebook] = "facebook";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.ProfileTwitter] = "twitter";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.ProfileLinkedIn] = "linkedin";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.ProfileGist] = "gist";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.ProfileTungle] = "tungle";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.DateBirthday] = "birthday";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.DateAnniversary] = "anniversary";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.NameGiven] = "givenName";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.NameSurname] = "familyName";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.Title] = "honorificPrefix";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.NameSuffix] = "honorificSuffix";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.NameMiddle] = "middleName";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.NamePhoneticGiven] = "phoneticGivenName";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.NamePhoneticSurname] = "phoneticFamilyName";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.NameNickname] = "nickname";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.NameDisplayName] = "displayName";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.OrganizationAffiliationName] = "name";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.OrganizationAffiliationDetails] = "department";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.Title] = "title";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingBbmPin] = "BbmPin";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingAim] = "Aim";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingAliwangwang] = "Aliwangwang";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingGoogleTalk] = "GoogleTalk";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingSametime] = "Sametime";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingIcq] = "Icq";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingJabber] = "Jabber";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingMsLcs] = "MsLcs";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingSkype] = "Skype";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingYahooMessenger] = "YahooMessenger";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.InstantMessagingYahooMessengerJapan] = "YahooMessegerJapan";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.VideoChatBbPlaybook] = "BbPlaybook";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.SoundRingtone] = "ringtone";
+    subKindAttributeMap[ATTRIBUTE_SUBKIND.Personal] = "personal";
+}
+
+module.exports = {
+    getKindAttributeMap: function () {
+        if (!ATTRIBUTE_KIND) {
+            populateKindAttributeMap();
+        }
+
+        return kindAttributeMap;
+    },
+    getSubKindAttributeMap: function () {
+        if (!ATTRIBUTE_SUBKIND) {
+            populateSubKindAttributeMap();
+        }
+
+        return subKindAttributeMap;
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Contacts/src/blackberry10/contactUtils.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Contacts/src/blackberry10/contactUtils.js b/blackberry10/plugins/Contacts/src/blackberry10/contactUtils.js
new file mode 100644
index 0000000..cd022c4
--- /dev/null
+++ b/blackberry10/plugins/Contacts/src/blackberry10/contactUtils.js
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2012 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 self,
+    ContactFindOptions = require("./ContactFindOptions"),
+    ContactError = require("./ContactError"),
+    ContactName = require("./ContactName"),
+    ContactOrganization = require("./ContactOrganization"),
+    ContactAddress = require("./ContactAddress"),
+    ContactField = require("./ContactField"),
+    contactConsts = require("./contactConsts"),
+    ContactPhoto = require("./ContactPhoto"),
+    ContactNews = require("./ContactNews"),
+    ContactActivity = require("./ContactActivity");
+
+function populateFieldArray(contactProps, field, ClassName) {
+    if (contactProps[field]) {
+        var list = [],
+        obj;
+
+        contactProps[field].forEach(function (args) {
+            if (ClassName === ContactField) {
+                list.push(new ClassName(args.type, args.value));
+            } else if (ClassName === ContactPhoto) {
+                obj = new ContactPhoto(args.originalFilePath, args.pref);
+                obj.largeFilePath = args.largeFilePath;
+                obj.smallFilePath = args.smallFilePath;
+                list.push(obj);
+            } else if (ClassName === ContactNews) {
+                obj = new ContactNews(args);
+                list.push(obj);
+            } else if (ClassName === ContactActivity) {
+                obj = new ContactActivity(args);
+                list.push(obj);
+            } else {
+                list.push(new ClassName(args));
+            }
+        });
+        contactProps[field] = list;
+    }
+}
+
+function populateDate(contactProps, field) {
+    if (contactProps[field]) {
+        contactProps[field] = new Date(contactProps[field]);
+    }
+}
+
+function validateFindArguments(findOptions) {
+    var error = false;
+    
+    // findOptions is mandatory
+    if (!findOptions) {
+        error = true;
+    } else {
+        // findOptions.filter is optional
+        if (findOptions.filter) {
+            findOptions.filter.forEach(function (f) {
+                switch (f.fieldName) {
+                case ContactFindOptions.SEARCH_FIELD_GIVEN_NAME:
+                case ContactFindOptions.SEARCH_FIELD_FAMILY_NAME:
+                case ContactFindOptions.SEARCH_FIELD_ORGANIZATION_NAME:
+                case ContactFindOptions.SEARCH_FIELD_PHONE:
+                case ContactFindOptions.SEARCH_FIELD_EMAIL:
+                case ContactFindOptions.SEARCH_FIELD_BBMPIN:
+                case ContactFindOptions.SEARCH_FIELD_LINKEDIN:
+                case ContactFindOptions.SEARCH_FIELD_TWITTER:
+                case ContactFindOptions.SEARCH_FIELD_VIDEO_CHAT:
+                    break;
+                default:
+                    error = true;
+                }
+
+                if (!f.fieldValue) {
+                    error = true;
+                }
+            });
+        } 
+
+        //findOptions.limit is optional
+        if (findOptions.limit) {
+            if (typeof findOptions.limit !== "number") {
+                error = true;
+            } 
+        } 
+
+        //findOptions.favorite is optional
+        if (findOptions.favorite) {
+            if (typeof findOptions.favorite !== "boolean") {
+                error = true;
+            }
+        }
+
+        // findOptions.sort is optional
+        if (!error && findOptions.sort && Array.isArray(findOptions.sort)) {
+            findOptions.sort.forEach(function (s) {
+                switch (s.fieldName) {
+                case ContactFindOptions.SORT_FIELD_GIVEN_NAME:
+                case ContactFindOptions.SORT_FIELD_FAMILY_NAME:
+                case ContactFindOptions.SORT_FIELD_ORGANIZATION_NAME:
+                    break;
+                default:
+                    error = true;
+                }
+
+                if (s.desc === undefined || typeof s.desc !== "boolean") {
+                    error = true;
+                }
+            });
+        }
+
+        if (!error && findOptions.includeAccounts) {
+            if (!Array.isArray(findOptions.includeAccounts)) {
+                error = true;
+            } else {
+                findOptions.includeAccounts.forEach(function (acct) {
+                    if (!error && (!acct.id || window.isNaN(window.parseInt(acct.id, 10)))) {
+                        error = true;
+                    }
+                });
+            }
+        }
+
+        if (!error && findOptions.excludeAccounts) {
+            if (!Array.isArray(findOptions.excludeAccounts)) {
+                error = true;
+            } else {
+                findOptions.excludeAccounts.forEach(function (acct) {
+                    if (!error && (!acct.id || window.isNaN(window.parseInt(acct.id, 10)))) {
+                        error = true;
+                    }
+                });
+            }
+        }
+    }
+    return !error;
+}
+
+function validateContactsPickerFilter(filter) {
+    var isValid = true,
+        availableFields = {};
+
+    if (typeof(filter) === "undefined") {
+        isValid = false;
+    } else {
+        if (filter && Array.isArray(filter)) {
+            availableFields = contactConsts.getKindAttributeMap();
+            filter.forEach(function (e) {
+                isValid = isValid && Object.getOwnPropertyNames(availableFields).reduce(
+                    function (found, key) {
+                        return found || availableFields[key] === e;
+                    }, false);
+            });
+        }
+    }
+
+    return isValid;
+}
+
+function validateContactsPickerOptions(options) {
+    var isValid = false,
+        mode = options.mode;
+
+    if (typeof(options) === "undefined") {
+        isValid = false;
+    } else {
+        isValid = mode === ContactPickerOptions.MODE_SINGLE || mode === ContactPickerOptions.MODE_MULTIPLE || mode === ContactPickerOptions.MODE_ATTRIBUTE;
+
+        // if mode is attribute, fields must be defined
+        if (mode === ContactPickerOptions.MODE_ATTRIBUTE && !validateContactsPickerFilter(options.fields)) {
+            isValid = false;
+        }
+    }
+
+    return isValid;
+}
+
+self = module.exports = {
+    populateContact: function (contact) {
+        if (contact.name) {
+            contact.name = new ContactName(contact.name);
+        }
+
+        populateFieldArray(contact, "addresses", ContactAddress);
+        populateFieldArray(contact, "organizations", ContactOrganization);
+        populateFieldArray(contact, "emails", ContactField);
+        populateFieldArray(contact, "phoneNumbers", ContactField);
+        populateFieldArray(contact, "faxNumbers", ContactField);
+        populateFieldArray(contact, "pagerNumbers", ContactField);
+        populateFieldArray(contact, "ims", ContactField);
+        populateFieldArray(contact, "socialNetworks", ContactField);
+        populateFieldArray(contact, "urls", ContactField);
+        populateFieldArray(contact, "photos", ContactPhoto);
+        populateFieldArray(contact, "news", ContactNews);
+        populateFieldArray(contact, "activities", ContactActivity);
+        // TODO categories
+
+        populateDate(contact, "birthday");
+        populateDate(contact, "anniversary");
+    },
+    invokeErrorCallback: function (errorCallback, code) {
+        if (errorCallback) {
+            errorCallback(new ContactError(code));
+        }
+    },
+    validateFindArguments: validateFindArguments,
+    validateContactsPickerFilter: validateContactsPickerFilter,
+    validateContactsPickerOptions: validateContactsPickerOptions
+};
+

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Contacts/src/blackberry10/index.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Contacts/src/blackberry10/index.js b/blackberry10/plugins/Contacts/src/blackberry10/index.js
new file mode 100644
index 0000000..09a4bd2
--- /dev/null
+++ b/blackberry10/plugins/Contacts/src/blackberry10/index.js
@@ -0,0 +1,374 @@
+/*
+ * Copyright 2013 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 pimContacts,
+    contactUtils = require("./contactUtils"),
+    contactConsts = require("./contactConsts"),
+    ContactError = require("./ContactError"),
+    ContactName = require("./ContactName"),
+    ContactFindOptions = require("./ContactFindOptions"),
+    noop = function () {};
+
+function getAccountFilters(options) {
+    if (options.includeAccounts) {
+        options.includeAccounts = options.includeAccounts.map(function (acct) {
+            return acct.id.toString();
+        });
+    }
+
+    if (options.excludeAccounts) {
+        options.excludeAccounts = options.excludeAccounts.map(function (acct) {
+            return acct.id.toString();
+        });
+    }
+}
+
+function populateSearchFields(fields) {
+    var i,
+        l,
+        key,
+        searchFieldsObject = {},
+        searchFields = [];
+
+    for (i = 0, l = fields.length; i < l; i++) {
+        if (fields[i] === "*") {
+            searchFieldsObject[ContactFindOptions.SEARCH_FIELD_GIVEN_NAME] = true;
+            searchFieldsObject[ContactFindOptions.SEARCH_FIELD_FAMILY_NAME] = true;
+            searchFieldsObject[ContactFindOptions.SEARCH_FIELD_PHONE] = true;
+            searchFieldsObject[ContactFindOptions.SEARCH_FIELD_EMAIL] = true;
+            searchFieldsObject[ContactFindOptions.SEARCH_FIELD_ORGANIZATION_NAME] = true;
+        } else if (fields[i] === "displayName" || fields[i] === "name") {
+            searchFieldsObject[ContactFindOptions.SEARCH_FIELD_GIVEN_NAME] = true;
+            searchFieldsObject[ContactFindOptions.SEARCH_FIELD_FAMILY_NAME] = true;
+        } else if (fields[i] === "nickname") {
+            // not supported by Cascades
+        } else if (fields[i] === "phoneNumbers") {
+            searchFieldsObject[ContactFindOptions.SEARCH_FIELD_PHONE] = true;
+        } else if (fields[i] === "emails") {
+            searchFieldsObject[ContactFindOptions.SEARCH_FIELD_EMAIL] = true;
+        } else if (field === "addresses") {
+            // not supported by Cascades
+        } else if (field === "ims") {
+            // not supported by Cascades
+        } else if (field === "organizations") {
+            searchFieldsObject[ContactFindOptions.SEARCH_FIELD_ORGANIZATION_NAME] = true;
+        } else if (field === "birthday") {
+            // not supported by Cascades
+        } else if (field === "note") {
+            // not supported by Cascades
+        } else if (field === "photos") {
+            // not supported by Cascades
+        } else if (field === "categories") {
+            // not supported by Cascades
+        } else if (field === "urls") {
+            // not supported by Cascades
+        }
+    }
+
+    for (key in searchFieldsObject) {
+        if (searchFieldsObject.hasOwnProperty(key)) {
+            searchFields.push(window.parseInt(key));
+        }
+    }
+
+    return searchFields;
+}
+
+function convertBirthday(birthday) {
+    //Convert date string from native to milliseconds since epoch for cordova-js
+    var birthdayInfo;
+    if (birthday) {
+        birthdayInfo = birthday.split("-");
+        return new Date(birthdayInfo[0], birthdayInfo[1] - 1, birthdayInfo[2]).getTime();
+    } else {
+        return null;
+    }
+}
+
+function processJnextSaveData(result, JnextData) {
+    var data = JnextData,
+        birthdayInfo;
+
+    if (data._success === true) {
+        data.birthday = convertBirthday(data.birthday);
+        result.callbackOk(data, false);
+    } else {
+        result.callbackError(data.code, false);
+    }
+}
+
+function processJnextRemoveData(result, JnextData) {
+    var data = JnextData;
+
+    if (data._success === true) {
+        result.callbackOk(data);
+    } else {
+        result.callbackError(ContactError.UNKNOWN_ERROR, false);
+    }
+}
+
+function processJnextFindData(eventId, eventHandler, JnextData) {
+    var data = JnextData,
+        i,
+        l,
+        more = false,
+        resultsObject = {},
+        birthdayInfo;
+
+    if (data.contacts) {
+        for (i = 0, l = data.contacts.length; i < l; i++) {
+            data.contacts[i].birthday = convertBirthday(data.contacts[i].birthday);
+            data.contacts[i].name = new ContactName(data.contacts[i].name);
+        }
+    } else {
+        data.contacts = []; // if JnextData.contacts return null, return an empty array
+    }
+
+    if (data._success === true) {
+        eventHandler.error = false;
+    }
+
+    if (eventHandler.multiple) {
+        // Concatenate results; do not add the same contacts
+        for (i = 0, l = eventHandler.searchResult.length; i < l; i++) {
+            resultsObject[eventHandler.searchResult[i].id] = true;
+        }
+
+        for (i = 0, l = data.contacts.length; i < l; i++) {
+            if (resultsObject[data.contacts[i].id]) {
+                // Already existing
+            } else {
+                eventHandler.searchResult.push(data.contacts[i]);
+            }
+        }
+
+        // check if more search is required
+        eventHandler.searchFieldIndex++;
+        if (eventHandler.searchFieldIndex < eventHandler.searchFields.length) {
+            more = true;
+        }
+    } else {
+        eventHandler.searchResult = data.contacts;
+    }
+
+    if (more) {
+        pimContacts.getInstance().invokeJnextSearch(eventId);
+    } else {
+        if (eventHandler.error) {
+            eventHandler.result.callbackError(data.code, false);
+        } else {
+            eventHandler.result.callbackOk(eventHandler.searchResult, false);
+        }
+    }
+}
+
+module.exports = {
+    search: function (successCb, failCb, args, env) {
+        var cordovaFindOptions = {},
+            result = new PluginResult(args, env),
+            key;
+
+        for (key in args) {
+            if (args.hasOwnProperty(key)) {
+                cordovaFindOptions[key] = JSON.parse(decodeURIComponent(args[key]));
+            }
+        }
+
+        pimContacts.getInstance().find(cordovaFindOptions, result, processJnextFindData);
+        result.noResult(true);
+    },
+    save: function (successCb, failCb, args, env) {
+        var attributes = {},
+            result = new PluginResult(args, env),
+            key,
+            nativeEmails = [];
+
+        attributes = JSON.parse(decodeURIComponent(args[0]));
+
+        //convert birthday format for our native .so file
+        if (attributes.birthday) {
+            attributes.birthday = new Date(attributes.birthday).toDateString();
+        }
+
+        if (attributes.emails) {
+            attributes.emails.forEach(function (email) {
+                if (email.value) {
+                    if (email.type) {
+                        nativeEmails.push({ "type" : email.type, "value" : email.value });
+                    } else {
+                        nativeEmails.push({ "type" : "home", "value" : email.value });
+                    }
+                }
+            });
+            attributes.emails = nativeEmails;
+        }
+
+        if (attributes.id !== null) {
+            attributes.id = window.parseInt(attributes.id);
+        }
+
+        attributes._eventId = result.callbackId;
+        pimContacts.getInstance().save(attributes, result, processJnextSaveData);
+        result.noResult(true);
+    },
+    remove: function (successCb, failCb, args, env) {
+        var result = new PluginResult(args, env),
+            attributes = {
+                "contactId": window.parseInt(JSON.parse(decodeURIComponent(args[0]))),
+                "_eventId": result.callbackId
+            };
+
+        if (!window.isNaN(attributes.contactId)) {
+            pimContacts.getInstance().remove(attributes, result, processJnextRemoveData);
+            result.noResult(true);
+        } else {
+            result.error(ContactError.UNKNOWN_ERROR);
+            result.noResult(false);
+        }
+    }
+};
+
+///////////////////////////////////////////////////////////////////
+// JavaScript wrapper for JNEXT plugin
+///////////////////////////////////////////////////////////////////
+
+JNEXT.PimContacts = function ()
+{
+    var self = this,
+        hasInstance = false;
+
+    self.find = function (cordovaFindOptions, pluginResult, handler) {
+        //register find eventHandler for when JNEXT onEvent fires
+        self.eventHandlers[cordovaFindOptions.callbackId] = {
+            "result" : pluginResult,
+            "action" : "find",
+            "multiple" : cordovaFindOptions[1].filter ? true : false,
+            "fields" : cordovaFindOptions[0],
+            "searchFilter" : cordovaFindOptions[1].filter,
+            "searchFields" : cordovaFindOptions[1].filter ? populateSearchFields(cordovaFindOptions[0]) : null,
+            "searchFieldIndex" : 0,
+            "searchResult" : [],
+            "handler" : handler,
+            "error" : true
+        };
+
+        self.invokeJnextSearch(cordovaFindOptions.callbackId);
+        return "";
+    };
+
+    self.invokeJnextSearch = function(eventId) {
+        var jnextArgs = {},
+            findHandler = self.eventHandlers[eventId];
+
+        jnextArgs._eventId = eventId;
+        jnextArgs.fields = findHandler.fields;
+        jnextArgs.options = {};
+        jnextArgs.options.filter = [];
+
+        if (findHandler.multiple) {
+            jnextArgs.options.filter.push({
+                "fieldName" : findHandler.searchFields[findHandler.searchFieldIndex],
+                "fieldValue" : findHandler.searchFilter
+            });
+            //findHandler.searchFieldIndex++;
+        }
+
+        JNEXT.invoke(self.m_id, "find " + JSON.stringify(jnextArgs));
+    }
+
+    self.getContact = function (args) {
+        return JSON.parse(JNEXT.invoke(self.m_id, "getContact " + JSON.stringify(args)));
+    };
+
+    self.save = function (args, pluginResult, handler) {
+        //register save eventHandler for when JNEXT onEvent fires
+        self.eventHandlers[args._eventId] = {
+            "result" : pluginResult,
+            "action" : "save",
+            "handler" : handler
+        };
+        JNEXT.invoke(self.m_id, "save " + JSON.stringify(args));
+        return "";
+    };
+
+    self.remove = function (args, pluginResult, handler) {
+        //register remove eventHandler for when JNEXT onEvent fires
+        self.eventHandlers[args._eventId] = {
+            "result" : pluginResult,
+            "action" : "remove",
+            "handler" : handler
+        };
+        JNEXT.invoke(self.m_id, "remove " + JSON.stringify(args));
+        return "";
+    };
+
+    self.getId = function () {
+        return self.m_id;
+    };
+
+    self.getContactAccounts = function () {
+        var value = JNEXT.invoke(self.m_id, "getContactAccounts");
+        return JSON.parse(value);
+    };
+
+    self.init = function () {
+        if (!JNEXT.require("libpimcontacts")) {
+            return false;
+        }
+
+        self.m_id = JNEXT.createObject("libpimcontacts.PimContacts");
+
+        if (self.m_id === "") {
+            return false;
+        }
+
+        JNEXT.registerEvents(self);
+    };
+
+    // Handle data coming back from JNEXT native layer. Each async function registers a handler and a PluginResult object.
+    // When JNEXT fires onEvent we parse the result string  back into JSON and trigger the appropriate handler (eventHandlers map
+    // uses callbackId as key), along with the actual data coming back from the native layer. Each function may have its own way of
+    // processing native data so we do not do any processing here.
+
+    self.onEvent = function (strData) {
+        var arData = strData.split(" "),
+            strEventDesc = arData[0],
+            eventHandler,
+            args = {};
+
+        if (strEventDesc === "result") {
+            args.result = escape(strData.split(" ").slice(2).join(" "));
+            eventHandler = self.eventHandlers[arData[1]];
+            if (eventHandler.action === "save" || eventHandler.action === "remove") {
+                eventHandler.handler(eventHandler.result, JSON.parse(decodeURIComponent(args.result)));
+            } else if (eventHandler.action === "find") {
+                eventHandler.handler(arData[1], eventHandler, JSON.parse(decodeURIComponent(args.result)));
+            }
+        }
+    };
+
+    self.m_id = "";
+    self.eventHandlers = {};
+
+    self.getInstance = function () {
+        if (!hasInstance) {
+            self.init();
+            hasInstance = true;
+        }
+        return self;
+    };
+};
+
+pimContacts = new JNEXT.PimContacts();

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Device/plugin.xml
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Device/plugin.xml b/blackberry10/plugins/Device/plugin.xml
new file mode 100644
index 0000000..db8b205
--- /dev/null
+++ b/blackberry10/plugins/Device/plugin.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+
+-->
+
+<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
+    id="org.apache.cordova.core.Device"
+    version="0.0.1">
+
+    <name>Device</name>
+
+    <platform name="blackberry10">
+        <source-file src="src/blackberry10/index.js" target-dir="Device" />
+        <config-file target="www/config.xml" parent="/widget">
+            <feature name="Device" value="Device"/>
+        </config-file>
+    </platform>
+</plugin>

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Device/src/blackberry10/index.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Device/src/blackberry10/index.js b/blackberry10/plugins/Device/src/blackberry10/index.js
new file mode 100644
index 0000000..89a40e4
--- /dev/null
+++ b/blackberry10/plugins/Device/src/blackberry10/index.js
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010-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.
+ */
+
+function getModelName () {
+    var modelName = window.qnx.webplatform.device.modelName;
+    //Pre 10.2 (meaning Z10 or Q10)
+    if (typeof modelName === "undefined") {
+        if (window.screen.height === 720 && window.screen.width === 720) {
+            modelName = "Q10";
+        } else if ((window.screen.height === 1280 && window.screen.width === 768) ||
+                   (window.screen.height === 768 && window.screen.width === 1280)) {
+            modelName = "Z10";
+        } else {
+            modelName = window.qnx.webplatform.deviceName;
+        }
+    }
+
+    return modelName;
+}
+
+function getUUID () {
+    var uuid = "";
+    try {
+        //Must surround by try catch because this will throw if the app is missing permissions
+        uuid = window.qnx.webplatform.device.devicePin;
+    } catch (e) {
+        //DO Nothing
+    }
+    return uuid;
+}
+
+module.exports = {
+    getDeviceInfo: function (success, fail, args, env) {
+        var result = new PluginResult(args, env),
+            modelName = getModelName(),
+            uuid = getUUID(),
+            info = {
+                platform: "blackberry10",
+                version: window.qnx.webplatform.device.scmBundle,
+                model: modelName,
+                name: modelName, // deprecated: please use device.model
+                uuid: uuid,
+                cordova: "dev"
+            };
+        result.ok(info);
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Logger/plugin.xml
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Logger/plugin.xml b/blackberry10/plugins/Logger/plugin.xml
new file mode 100644
index 0000000..f930d15
--- /dev/null
+++ b/blackberry10/plugins/Logger/plugin.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+
+-->
+
+<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
+    id="org.apache.cordova.core.Logger"
+    version="0.0.1">
+
+    <name>Logger</name>
+
+    <platform name="blackberry10">
+        <source-file src="src/blackberry10/index.js" target-dir="Logger" />
+        <config-file target="www/config.xml" parent="/widget">
+            <feature name="Logger" value="Logger"/>
+        </config-file>
+    </platform>
+</plugin>

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/Logger/src/blackberry10/index.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/Logger/src/blackberry10/index.js b/blackberry10/plugins/Logger/src/blackberry10/index.js
new file mode 100644
index 0000000..497f477
--- /dev/null
+++ b/blackberry10/plugins/Logger/src/blackberry10/index.js
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2010-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.
+ */
+
+module.exports = {
+    logLevel: function (success, fail, args, env) {
+        var result = new PluginResult(args, env),
+            level = JSON.parse(decodeURIComponent(args[0])),
+            message = JSON.parse(decodeURIComponent(args[1]));
+        console.log(level + ": " + message);
+        result.noResult(false);
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/NetworkStatus/plugin.xml
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/NetworkStatus/plugin.xml b/blackberry10/plugins/NetworkStatus/plugin.xml
new file mode 100644
index 0000000..47eea68
--- /dev/null
+++ b/blackberry10/plugins/NetworkStatus/plugin.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+
+-->
+
+<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
+    id="org.apache.cordova.core.Network"
+    version="0.0.1">
+
+    <name>Network Information</name>
+
+    <platform name="blackberry10">
+        <source-file src="src/blackberry10/index.js" target-dir="NetworkStatus" />
+        <config-file target="www/config.xml" parent="/widget">
+            <feature name="NetworkStatus" value="NetworkStatus"/>
+        </config-file>
+    </platform>
+</plugin>

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/fa5a5900/blackberry10/plugins/NetworkStatus/src/blackberry10/index.js
----------------------------------------------------------------------
diff --git a/blackberry10/plugins/NetworkStatus/src/blackberry10/index.js b/blackberry10/plugins/NetworkStatus/src/blackberry10/index.js
new file mode 100644
index 0000000..5a991fe
--- /dev/null
+++ b/blackberry10/plugins/NetworkStatus/src/blackberry10/index.js
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010-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.
+ */
+
+//map from BB10 to cordova connection types:
+//https://github.com/apache/cordova-js/blob/master/lib/common/plugin/Connection.js
+function mapConnectionType(con) {
+    switch (con.type) {
+    case 'wired':
+        return 'ethernet';
+    case 'wifi':
+        return 'wifi';
+    case 'none':
+        return 'none';
+    case 'cellular':
+        switch (con.technology) {
+        case 'edge':
+        case 'gsm':
+            return '2g';
+        case 'evdo':
+            return '3g';
+        case 'umts':
+            return '3g';
+        case 'lte':
+            return '4g';
+        }
+        return "cellular";
+    }
+    return 'unknown';
+}
+
+function currentConnectionType() {
+    try {
+        //possible for webplatform to throw pps exception
+        return mapConnectionType(window.qnx.webplatform.device.activeConnection || { type : 'none' });
+    }
+    catch (e) {
+        return 'unknown';
+    }
+}
+
+module.exports = {
+    getConnectionInfo: function (success, fail, args, env) {
+        var result = new PluginResult(args, env);
+        result.ok(currentConnectionType());
+    }
+};