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

[28/38] updated android, ios, bb libraries to 2.8.x branch. fixed a few assertions with project changes. removed blackberry support until create script can be finalized.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/88ad654c/lib/cordova-blackberry/bin/templates/project/cordova/lib/config-parser.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/cordova/lib/config-parser.js b/lib/cordova-blackberry/bin/templates/project/cordova/lib/config-parser.js
new file mode 100644
index 0000000..0e3d9e9
--- /dev/null
+++ b/lib/cordova-blackberry/bin/templates/project/cordova/lib/config-parser.js
@@ -0,0 +1,670 @@
+/*
+ *  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.
+ */
+/*jshint sub:true*/
+var fs = require("fs"),
+    util = require('util'),
+    xml2js = require('xml2js'),
+    packagerUtils = require('./packager-utils'),
+    check = require('validator').check,
+    sanitize = require('validator').sanitize,
+    localize = require("./localize"),
+    logger = require("./logger"),
+    fileManager = require("./file-manager"),
+    utils = require("./packager-utils"),
+    i18nMgr = require("./i18n-manager"),
+    _self,
+    _predefinedFeatures,
+    _hybridFeatures;
+
+//This function will convert a wc3 paramObj with a list of
+//<param name="" value=""> elements into a single object
+function processParamObj(paramObj) {
+    var processedObj = {},
+        attribs,
+        paramName,
+        paramValue;
+
+    if (paramObj) {
+        //Convert to array for single param entries where only an object is created
+        if (!Array.isArray(paramObj)) {
+            paramObj = [paramObj];
+        }
+
+        paramObj.forEach(function (param) {
+            attribs = param["@"];
+
+            if (attribs) {
+                paramName = attribs["name"];
+                paramValue = attribs["value"];
+
+                if (paramName && paramValue) {
+                    //Add the key/value pair to the processedObj
+                    processedObj[paramName] = paramValue;
+                }
+            }
+        });
+    }
+
+    return processedObj;
+}
+
+function processFeatures(featuresArray, widgetConfig, processPredefinedFeatures) {
+    var features = [],
+        attribs;
+    if (featuresArray) {
+        featuresArray.forEach(function (feature) {
+            attribs = feature["@"];
+            if (attribs) {
+                attribs.required = packagerUtils.toBoolean(attribs.required, true);
+
+                // We do NOT want to auto defer networking and JavaScript if the
+                // blackberry.push feature is being used
+                if (attribs.id === "blackberry.push") {
+                    widgetConfig.autoDeferNetworkingAndJavaScript = false;
+                }
+
+                if (_predefinedFeatures[attribs.id]) {
+                    //Handle features that do NOT contain an API namespace
+                    if (processPredefinedFeatures) {
+                        _predefinedFeatures[attribs.id](feature, widgetConfig);
+                    }
+                } else {
+                    //Handle features that contain both a namespace and custom params
+                    if (_hybridFeatures[attribs.id]) {
+                        _hybridFeatures[attribs.id](feature, widgetConfig);
+                    }
+                    features.push(attribs);
+                }
+            } else {
+                features.push(attribs);
+            }
+        });
+    }
+
+    return features;
+}
+
+function createAccessListObj(uri, allowSubDomain) {
+    return {
+        uri: uri,
+        allowSubDomain: allowSubDomain
+    };
+}
+
+function processVersion(widgetConfig) {
+    if (widgetConfig.version) {
+        var versionArray = widgetConfig.version.split(".");
+
+        //if 4rth number in version exists, extract for build id
+        if (versionArray.length > 3) {
+            widgetConfig.buildId = versionArray[3];
+            widgetConfig.version = widgetConfig.version.substring(0, widgetConfig.version.lastIndexOf('.'));
+        }
+    }
+}
+
+function processBuildID(widgetConfig, session) {
+    if (session.buildId) {
+        //user specified a build id (--buildId), overide any previously set build id
+        widgetConfig.buildId = session.buildId;
+    }
+}
+
+function processWidgetData(data, widgetConfig, session) {
+    var attribs, featureArray, header;
+
+    if (data["@"]) {
+        widgetConfig.version = data["@"].version;
+        widgetConfig.id = data["@"].id;
+
+        if (data["@"]["rim:header"]) {
+            widgetConfig.customHeaders = {};
+            header = data["@"]["rim:header"].split(":");
+            // Just set it for now, in the future we can append them
+            widgetConfig.customHeaders[header[0]] = header[1];
+        }
+
+        if (data["@"]["rim:userAgent"]) {
+            widgetConfig.userAgent = data["@"]["rim:userAgent"];
+        }
+    }
+
+    //Default values
+    widgetConfig.hasMultiAccess = false;
+    widgetConfig.accessList = [];
+    widgetConfig.enableFlash = false;
+    widgetConfig.autoOrientation = true;
+    widgetConfig.autoDeferNetworkingAndJavaScript = true;
+    widgetConfig.theme = "default";
+    widgetConfig.autoHideSplashScreen = "true";
+
+    //set locally available features to access list
+   if (data.feature) {
+        featureArray = packagerUtils.isArray(data.feature) ? data.feature : [data.feature];
+    }
+
+    //Handle features that do not have source code
+    featureArray = processFeatures(featureArray, widgetConfig, true);
+
+    //Push empty WIDGET_LOCAL access obj until whitelisting is cleaned up
+    widgetConfig.accessList.push(createAccessListObj("WIDGET_LOCAL", true));
+
+    //add whitelisted features to access list
+    if (data.access) {
+        //If there is only one access list element, it will be parsed as an object and not an array
+        if (!packagerUtils.isArray(data.access)) {
+            data.access = [data.access];
+        }
+
+        data.access.forEach(function (accessElement) {
+            attribs = accessElement["@"];
+
+            if (attribs) {
+                if (attribs.uri === "*") {
+                    if (accessElement.feature) {
+                        throw localize.translate("EXCEPTION_FEATURE_DEFINED_WITH_WILDCARD_ACCESS_URI");
+                    }
+
+                    widgetConfig.hasMultiAccess = true;
+                } else {
+                    attribs.subdomains = packagerUtils.toBoolean(attribs.subdomains);
+                    widgetConfig.accessList.push(createAccessListObj(attribs.uri, attribs.subdomains));
+                }
+            }
+        });
+    }
+}
+
+function trim(obj) {
+    return (typeof obj === "string" ? obj.trim() : obj);
+}
+
+function processSplashScreenIconSrc(data, widgetConfig, key) {
+    if (data[key]) {
+        widgetConfig[key] = [];
+
+        if (!(data[key] instanceof Array)) {
+            data[key] = [data[key]];
+        }
+
+        data[key].forEach(function (obj) {
+            if (obj["@"]) {
+                widgetConfig[key].push(obj["@"].src);
+            } else {
+                widgetConfig[key].push(obj);
+            }
+        });
+    }
+}
+
+function processSplashScreenData(data, widgetConfig) {
+    //
+    // This takes config.xml markup in the form of:
+    //
+    // <rim:splash src="splash-1280x768.jpg" />
+    // <rim:splash src="splash-768x1280.jpg" />
+    // <rim:splash src="splash-1024x600.jpg" />
+    // <rim:splash src="splash-600x1024.jpg" />
+    //
+    // and turns it into:
+    //
+    // icon: ["splash-1280x768.jpg", "splash-768x1280.jpg", "splash-1024x600.jpg", "splash-600x1024.jpg"]
+    //
+    // Folder-based localization now done in i18n-manager
+    //
+    processSplashScreenIconSrc(data, widgetConfig, "rim:splash");
+}
+
+function processIconData(data, widgetConfig, session) {
+    //
+    // This takes config.xml markup in the form of:
+    //
+    // <icon src="icon-86.png" />
+    // <icon src="icon-150.png" />
+    //
+    // and turns it into:
+    //
+    // icon: ["icon-86.png", "icon-150.png"]
+    //
+    // Folder-based localization now done in i18n-manager
+    //
+    var default_icon_filename = "default-icon.png",
+        default_icon_src = session.conf.DEFAULT_ICON,
+        default_icon_dst = session.sourceDir;
+
+    processSplashScreenIconSrc(data, widgetConfig, "icon");
+
+    if (!widgetConfig.icon) {
+        packagerUtils.copyFile(default_icon_src, default_icon_dst);
+
+        widgetConfig["icon"] = [];
+        widgetConfig["icon"].push(default_icon_filename);
+    }
+}
+
+function validateSplashScreensIcon(widgetConfig, key) {
+    if (widgetConfig[key]) {
+        var msg = localize.translate(key === "icon" ? "EXCEPTION_INVALID_ICON_SRC" : "EXCEPTION_INVALID_SPLASH_SRC");
+
+        if (widgetConfig[key].length === 0) {
+            // element without src attribute
+            throw msg;
+        } else {
+            widgetConfig[key].forEach(function (src) {
+                var msg2 = localize.translate(key === "icon" ? "EXCEPTION_INVALID_ICON_SRC_LOCALES" : "EXCEPTION_INVALID_SPLASH_SRC_LOCALES");
+
+                // check that src attribute is specified and is not empty
+                check(src, msg).notNull();
+
+                // check that src attribute does not start with reserved locales folder
+                src = src.replace(/\\/g, "/");
+                check(src, msg2).notRegex("^" + i18nMgr.LOCALES_DIR + "\/");
+            });
+        }
+
+    }
+}
+
+function processAuthorData(data, widgetConfig) {
+    if (data.author) {
+        var attribs = data.author["@"];
+
+        if (!attribs && typeof data.author === "string") {
+            //do not sanitize empty objects {} (must be string)
+            widgetConfig.author = sanitize(data.author).trim();
+        } else if (data.author["#"]) {
+            widgetConfig.author = sanitize(data.author["#"]).trim();
+        }
+
+        if (attribs) {
+            widgetConfig.authorURL = attribs.href;
+            widgetConfig.copyright = attribs["rim:copyright"];
+            widgetConfig.authorEmail = attribs.email;
+        }
+    }
+}
+
+function processLicenseData(data, widgetConfig) {
+    if (data.license && data.license["#"]) {
+        widgetConfig.license = data.license["#"];
+    } else {
+        widgetConfig.license = "";
+    }
+
+    if (data.license && data.license["@"]) {
+        widgetConfig.licenseURL = data.license["@"].href;
+    } else {
+        widgetConfig.licenseURL = "";
+    }
+}
+
+function processContentData(data, widgetConfig) {
+    if (data.content) {
+        var attribs  = data.content["@"],
+            startPage;
+        if (attribs) {
+            widgetConfig.content = attribs.src;
+
+            startPage = packagerUtils.parseUri(attribs.src);
+
+            // if start page is local but does not start with local:///, will prepend it
+            // replace any backslash with forward slash
+            if (!packagerUtils.isAbsoluteURI(startPage) && !packagerUtils.isLocalURI(startPage)) {
+                if (!startPage.relative.match(/^\//)) {
+                    widgetConfig.content = "local:///" + startPage.relative.replace(/\\/g, "/");
+                } else {
+                    widgetConfig.content = "local://" + startPage.relative.replace(/\\/g, "/");
+                }
+            }
+
+            widgetConfig.foregroundSource = attribs.src;
+            widgetConfig.contentType = attribs.type;
+            widgetConfig.contentCharSet = attribs.charset;
+            widgetConfig.allowInvokeParams = attribs["rim:allowInvokeParams"];
+            //TODO content rim:background
+        }
+    }
+}
+
+function processPermissionsData(data, widgetConfig) {
+    if (data["rim:permissions"] && data["rim:permissions"]["rim:permit"]) {
+        var permissions = data["rim:permissions"]["rim:permit"];
+
+        if (permissions instanceof Array) {
+            widgetConfig.permissions = permissions;
+        } else {
+            //user entered one permission and it comes in as an object
+            widgetConfig.permissions = [permissions];
+        }
+    } else {
+        widgetConfig.permissions = [];
+    }
+
+    // We do NOT want to auto defer networking and JavaScript if the
+    // run_when_backgrounded permission is set
+    if (widgetConfig.permissions.indexOf("run_when_backgrounded") >= 0) {
+        widgetConfig.autoDeferNetworkingAndJavaScript = false;
+    }
+}
+
+function processInvokeTargetsData(data, widgetConfig) {
+
+    if (data["rim:invoke-target"]) {
+        widgetConfig["invoke-target"] = data["rim:invoke-target"];
+
+        //If invoke-target is not an array, wrap the invoke-target in an array
+        utils.wrapPropertyInArray(widgetConfig, "invoke-target");
+
+        widgetConfig["invoke-target"].forEach(function (invokeTarget) {
+            if (invokeTarget.type && !packagerUtils.isEmpty(invokeTarget.type)) {
+                invokeTarget.type = invokeTarget.type.toUpperCase();
+            }
+
+            if (invokeTarget.filter) {
+                utils.wrapPropertyInArray(invokeTarget, "filter");
+
+                invokeTarget.filter.forEach(function (filter) {
+
+                    if (filter["action"]) {
+                        utils.wrapPropertyInArray(filter, "action");
+                    }
+
+                    if (filter["mime-type"]) {
+                        utils.wrapPropertyInArray(filter, "mime-type");
+                    }
+
+                    if (filter["property"]) {
+                        utils.wrapPropertyInArray(filter, "property");
+                    }
+                });
+            }
+        });
+    }
+}
+
+function validateConfig(widgetConfig) {
+    check(widgetConfig.version, localize.translate("EXCEPTION_INVALID_VERSION"))
+        .notNull()
+        .regex("^[0-9]{1,3}([.][0-9]{1,3}){2,3}$");
+
+    for (var prop in widgetConfig.name) {
+        if (widgetConfig.name.hasOwnProperty(prop)) {
+            check(widgetConfig.name[prop], localize.translate("EXCEPTION_INVALID_NAME")).notEmpty();
+        }
+    }
+
+    check(widgetConfig.author, localize.translate("EXCEPTION_INVALID_AUTHOR")).notNull();
+    check(widgetConfig.id, localize.translate("EXCEPTION_INVALID_ID")).notNull().notEmpty();
+    check(widgetConfig.content, localize.translate("EXCEPTION_INVALID_CONTENT"))
+        .notNull()
+        .notEmpty();
+
+    validateSplashScreensIcon(widgetConfig, "rim:splash");
+
+    validateSplashScreensIcon(widgetConfig, "icon");
+
+    if (widgetConfig.accessList) {
+        widgetConfig.accessList.forEach(function (access) {
+            if (access.uri) {
+                if (access.uri !== "WIDGET_LOCAL") {
+                    check(access.uri, localize.translate("EXCEPTION_INVALID_ACCESS_URI_NO_PROTOCOL", access.uri))
+                        .regex("^[a-zA-Z]+:\/\/");
+                    check(access.uri, localize.translate("EXCEPTION_INVALID_ACCESS_URI_NO_URN", access.uri))
+                        .notRegex("^[a-zA-Z]+:\/\/$");
+                }
+            }
+
+            if (access.features) {
+                // Assert each feature has a proper ID and is not empty
+                access.features.forEach(function (feature) {
+                    if (!feature) {
+                        throw localize.translate("EXCEPTION_INVALID_FEATURE_ID");
+                    }
+                    check(feature.id, localize.translate("EXCEPTION_INVALID_FEATURE_ID")).notNull().notEmpty();
+                });
+            }
+
+        });
+    }
+
+    if (widgetConfig["invoke-target"]) {
+
+        widgetConfig["invoke-target"].forEach(function (invokeTarget) {
+
+            check(typeof invokeTarget["@"] === "undefined",
+                    localize.translate("EXCEPTION_INVOKE_TARGET_INVALID_ID"))
+                .equals(false);
+            check(invokeTarget["@"].id, localize.translate("EXCEPTION_INVOKE_TARGET_INVALID_ID"))
+                .notNull()
+                .notEmpty();
+            check(invokeTarget.type, localize.translate("EXCEPTION_INVOKE_TARGET_INVALID_TYPE"))
+                .notNull()
+                .notEmpty();
+
+            if (invokeTarget.filter) {
+
+                invokeTarget.filter.forEach(function (filter) {
+
+                    check(filter["action"] && filter["action"] instanceof Array && filter["action"].length > 0,
+                            localize.translate("EXCEPTION_INVOKE_TARGET_ACTION_INVALID"))
+                        .equals(true);
+
+                    check(filter["mime-type"] && filter["mime-type"] instanceof Array && filter["mime-type"].length > 0,
+                            localize.translate("EXCEPTION_INVOKE_TARGET_MIME_TYPE_INVALID"))
+                        .equals(true);
+
+                    if (filter.property) {
+                        filter.property.forEach(function (property) {
+                            check(property["@"] && property["@"]["var"] && typeof property["@"]["var"] === "string",
+                                    localize.translate("EXCEPTION_INVOKE_TARGET_FILTER_PROPERTY_INVALID"))
+                                .equals(true);
+                        });
+                    }
+                });
+            }
+        });
+    }
+}
+
+function processLocalizedText(tag, data, widgetConfig) {
+    var tagData = data[tag],
+        DEFAULT = 'default';
+
+    function processLanguage(tagElement) {
+        var attribs = tagElement['@'],
+            language;
+
+        if (attribs) {
+            language = attribs['xml:lang'] || DEFAULT;
+            widgetConfig[tag][language.toLowerCase()] = tagElement['#'];
+        } else {
+            widgetConfig[tag][DEFAULT] = tagElement;
+        }
+    }
+
+    if (Array.isArray(tagData)) {
+        //i.e. <element xml:lang="en">english value</element>
+        //     <element xml:lang="fr">french value</element>
+        tagData.forEach(processLanguage);
+    } else if (tagData instanceof Object) {
+        //i.e. <element xml:lang="en">english value</element>
+        processLanguage(tagData);
+    } else {
+        //i.e <element>value</element>
+        widgetConfig[tag][DEFAULT] = tagData;
+    }
+}
+
+function processNameAndDescription(data, widgetConfig) {
+    widgetConfig.name = {};
+    widgetConfig.description = {};
+
+    processLocalizedText('name', data, widgetConfig);
+    processLocalizedText('description', data, widgetConfig);
+}
+
+function processCordovaPreferences(data, widgetConfig) {
+    if (data.preference) {
+        var preference = processParamObj(data.preference);
+        widgetConfig.packageCordovaJs = preference.packageCordovaJs === "enable";
+        widgetConfig.autoHideSplashScreen = preference.AutoHideSplashScreen !== "false";
+    }
+}
+
+function processResult(data, session) {
+    var widgetConfig = {};
+
+    processWidgetData(data, widgetConfig, session);
+    processIconData(data, widgetConfig, session);
+    processAuthorData(data, widgetConfig);
+    processLicenseData(data, widgetConfig);
+    processContentData(data, widgetConfig);
+    processPermissionsData(data, widgetConfig);
+    processInvokeTargetsData(data, widgetConfig);
+    processSplashScreenData(data, widgetConfig);
+    processNameAndDescription(data, widgetConfig);
+    processCordovaPreferences(data, widgetConfig);
+
+    widgetConfig.configXML = "config.xml";
+
+    //validate the widgetConfig
+    validateConfig(widgetConfig);
+
+    //special handling for version and grabbing the buildId if specified (4rth number)
+    processVersion(widgetConfig);
+
+    //if --buildId was specified, it takes precedence
+    processBuildID(widgetConfig, session);
+
+    return widgetConfig;
+}
+
+function init() {
+    //Predefined features are features that do NOT contain an API namespace
+    _predefinedFeatures = {
+        "enable-flash" : function (feature, widgetConfig) {
+            widgetConfig.enableFlash = true;
+        },
+        "blackberry.app.orientation": function (feature, widgetConfig) {
+            if (feature) {
+                var params = processParamObj(feature.param),
+                    mode = params.mode;
+
+                if (!mode) {
+                    //No mode provided, throw error
+                    throw localize.translate("EXCEPTION_EMPTY_ORIENTATION_MODE", mode);
+                } else if (mode === "landscape" || mode === "portrait" || mode === "north") {
+                    widgetConfig.autoOrientation = false;//Overwrites default value
+                    widgetConfig.orientation = mode;
+                } else if (mode !== "auto") {
+                    //Mode invalid, throw error
+                    throw localize.translate("EXCEPTION_INVALID_ORIENTATION_MODE", mode);
+                }
+
+                // Throw a warning since this feature is deprecated
+                logger.warn(localize.translate("WARNING_ORIENTATION_DEPRECATED"));
+            }
+        }
+    };
+
+    //Hybrid features are features that have both an API namespace and custom parameters
+    _hybridFeatures = {
+        "blackberry.app": function (feature, widgetConfig) {
+            if (feature) {
+                var params = processParamObj(feature.param),
+                    bgColor = params.backgroundColor,
+                    childBrowser = params.childBrowser,
+                    formControl = params.formControl,
+                    orientation = params.orientation,
+                    theme = params.theme,
+                    popupBlocker = params.popupBlocker,
+                    websecurity = params.websecurity;
+
+                if (bgColor) {
+                    //Convert bgColor to a number
+                    bgColor = parseInt(bgColor, 16);
+
+                    if (isNaN(bgColor)) {
+                        //bgcolor is not a number, throw error
+                        throw localize.translate("EXCEPTION_BGCOLOR_INVALID", params.backgroundColor);
+                    } else {
+                        widgetConfig.backgroundColor = bgColor;
+                    }
+                }
+
+                if (childBrowser) {
+                    widgetConfig.enableChildWebView = ((childBrowser + '').toLowerCase() === 'disable') === false;
+                }
+
+                if (formControl) {
+                    widgetConfig.enableFormControl = ((formControl + '').toLowerCase() === 'disable') === false;
+                }
+
+                if (popupBlocker) {
+                    widgetConfig.enablePopupBlocker = ((popupBlocker + '').toLowerCase() === 'enable') === true;
+                }
+
+                if (orientation) {
+                    if (orientation ===  "landscape" || orientation === "portrait" || orientation === "north") {
+                        widgetConfig.autoOrientation = false;
+                        widgetConfig.orientation = orientation;
+                    } else if (orientation !== "auto") {
+                        throw localize.translate("EXCEPTION_INVALID_ORIENTATION_MODE", orientation);
+                    }
+                }
+
+                if (theme && (typeof theme === "string")) {
+                    theme = theme.toLowerCase();
+
+                    if (theme ===  "bright" || theme === "dark" || theme === "inherit" || theme ===  "default") {
+                        widgetConfig.theme = theme;
+                    }
+                }
+
+                if (websecurity && (typeof websecurity === "string") && (websecurity.toLowerCase() === "disable")) {
+                    widgetConfig.enableWebSecurity = false;
+                    logger.warn(localize.translate("WARNING_WEBSECURITY_DISABLED"));
+                }
+            }
+        }
+    };
+}
+
+_self = {
+    parse: function (xmlPath, session, callback) {
+        if (!fs.existsSync(xmlPath)) {
+            throw localize.translate("EXCEPTION_CONFIG_NOT_FOUND");
+        }
+
+        var fileData = fs.readFileSync(xmlPath),
+            xml = utils.bufferToString(fileData),
+            parser = new xml2js.Parser({trim: true, normalize: true, explicitRoot: false});
+
+        init();
+
+        //parse xml file data
+        parser.parseString(xml, function (err, result) {
+            if (err) {
+                logger.error(localize.translate("EXCEPTION_PARSING_XML"));
+                fileManager.cleanSource(session);
+            } else {
+                callback(processResult(result, session));
+            }
+        });
+    }
+};
+
+module.exports = _self;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/88ad654c/lib/cordova-blackberry/bin/templates/project/cordova/lib/debugtoken-helper.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/cordova/lib/debugtoken-helper.js b/lib/cordova-blackberry/bin/templates/project/cordova/lib/debugtoken-helper.js
new file mode 100755
index 0000000..791973c
--- /dev/null
+++ b/lib/cordova-blackberry/bin/templates/project/cordova/lib/debugtoken-helper.js
@@ -0,0 +1,211 @@
+/*
+ *  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 childProcess = require("child_process"),
+    fs = require("fs"),
+    path = require("path"),
+    conf = require("./conf"),
+    localize = require("./localize"),
+    logger = require("./logger"),
+    pkgrUtils = require("./packager-utils"),
+    workingDir = path.normalize(__dirname + "/.."),
+    debugTokenDir = path.normalize(workingDir + "/" + "debugtoken.bar"),
+    properties,
+    targets,
+    deployCallback,
+    self = {};
+
+function generateCreateTokenOptions(pins, password) {
+    var options = [],
+        i;
+
+    options.push("-storepass");
+    options.push(password);
+
+    for (i = 0; i < pins.length; i++) {
+        options.push("-devicepin");
+        options.push(pins[i]);
+    }
+
+    options.push(debugTokenDir);
+
+    return options;
+}
+
+function generateDeployTokenOptions(target) {
+    var options = [];
+
+    options.push("-installDebugToken");
+    options.push(debugTokenDir);
+
+    options.push("-device");
+    options.push(properties.targets[target].ip);
+
+    options.push("-password");
+    options.push(properties.targets[target].password);
+
+    return options;
+}
+
+function execNativeScript(script, options, callback) {
+    var process;
+
+    if (pkgrUtils.isWindows()) {
+        script += ".bat";
+    }
+
+    if (fs.existsSync(conf.DEPENDENCIES_TOOLS)) {
+        process = childProcess.spawn(path.normalize(conf.DEPENDENCIES_TOOLS + script), options, {
+            "cwd" : workingDir,
+            "env" : process ? process.env : undefined
+        });
+
+        process.stdout.on("data", pkgrUtils.handleProcessOutput);
+
+        process.stderr.on("data", pkgrUtils.handleProcessOutput);
+
+        process.on("exit", function (code) {
+            if (callback && typeof callback === "function") {
+                callback(code);
+            }
+        });
+    } else {
+        throw localize.translate("EXCEPTION_MISSING_TOOLS");
+    }
+}
+
+function checkTarget(target) {
+    if (!properties.targets[target]) {
+        logger.warn(localize.translate("WARN_TARGET_NOT_EXIST", target));
+        return false;
+    }
+
+    if (!properties.targets[target].ip) {
+        logger.warn(localize.translate("WARN_IP_NOT_DEFINED", target));
+        return false;
+    }
+
+    if (!properties.targets[target].password) {
+        logger.warn(localize.translate("WARN_PASSWORD_NOT_DEFINED", target));
+        return false;
+    }
+
+    return true;
+
+}
+
+// Deploy the debug token for each target in targets array recursively
+function deployTokenToTargetsRecursively() {
+    var target;
+
+    if (targets.length > 0) {
+        target = targets.pop();
+
+        logger.info(localize.translate("PROGRESS_DEPLOYING_DEBUG_TOKEN", target));
+        if (checkTarget(target)) {
+            execNativeScript("/bin/blackberry-deploy",
+                generateDeployTokenOptions(target),
+                deployTokenToTargetsRecursively
+            );
+        } else {
+            deployTokenToTargetsRecursively();
+        }
+    } else {
+        if (deployCallback && typeof deployCallback === "function") {
+            deployCallback();
+        }
+    }
+}
+
+self.createToken = function (projectProperties, target, keystorepass, callback) {
+    var pins = [],
+        key;
+
+    // Store the global variable "properties"
+    properties = projectProperties;
+
+    // Gather PINs information from properties
+    if (target === "all") {
+        for (key in properties.targets) {
+            if (properties.targets.hasOwnProperty(key) && properties.targets[key].pin) {
+                pins.push(properties.targets[key].pin);
+            }
+        }
+    } else {
+        if (!target) {
+            target = properties.defaultTarget;
+        }
+
+        if (properties.targets.hasOwnProperty(target) && properties.targets[target].pin) {
+            pins.push(properties.targets[target].pin);
+        }
+    }
+
+    if (pins.length === 0) {
+        logger.warn(localize.translate("WARN_NO_DEVICE_PIN_FOUND"));
+        if (callback && typeof callback === "function") {
+            callback(-1);
+        }
+    } else if (!keystorepass) {
+        logger.warn(localize.translate("WARN_NO_SIGNING_PASSWORD_PROVIDED"));
+        if (callback && typeof callback === "function") {
+            callback(-1);
+        }
+    } else {
+        logger.info(localize.translate("PROGRESS_GENERATING_DEBUG_TOKEN"));
+        // Call "blackberry-debugtokenrequest" to generate debug token
+        execNativeScript("/bin/blackberry-debugtokenrequest",
+            generateCreateTokenOptions(pins, keystorepass),
+            callback
+        );
+    }
+};
+
+self.deployToken = function (projectProperties, target, callback) {
+    var key;
+
+    // Store the global variable "properties"
+    properties = projectProperties;
+
+    // Initialize the global variable "targets"
+    targets = [];
+
+    // Store callback so it will be invoked after debug token is deployed to all target(s)
+    deployCallback = callback;
+
+    // Gather targets information from properties
+    // Gather PINs information from properties
+    if (target === "all") {
+        for (key in properties.targets) {
+            if (properties.targets.hasOwnProperty(key) && properties.targets[key].pin) {
+                targets.push(key);
+            }
+        }
+    } else {
+        if (!target) {
+            target = properties.defaultTarget;
+        }
+
+        if (properties.targets.hasOwnProperty(target) && properties.targets[target].pin) {
+            targets.push(target);
+        }
+    }
+
+    // Deploy debug token recursively
+    deployTokenToTargetsRecursively();
+};
+
+module.exports = self;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/88ad654c/lib/cordova-blackberry/bin/templates/project/cordova/lib/file-manager.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/cordova/lib/file-manager.js b/lib/cordova-blackberry/bin/templates/project/cordova/lib/file-manager.js
new file mode 100755
index 0000000..1ce0cf3
--- /dev/null
+++ b/lib/cordova-blackberry/bin/templates/project/cordova/lib/file-manager.js
@@ -0,0 +1,208 @@
+/*
+ *  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 path = require("path"),
+    util = require("util"),
+    packagerUtils = require("./packager-utils"),
+    fs = require("fs"),
+    conf = require("./conf"),
+    BBWPignore = require('./bbwpignore'),
+    wrench = require("wrench"),
+    zip = require("zip"),
+    localize = require("./localize"),
+    logger = require("./logger"),
+    CLIENT_JS = "client.js",
+    SERVER_JS = "index.js",
+    VALID_EXTENSIONS = [".js", ".json"],
+    CORDOVA_JS_REGEX = /(cordova-.+js)|cordova\.js/;
+
+function unzip(from, to) {
+    var data, entries, p, parent;
+
+    if (fs.existsSync(from)) {
+        data = fs.readFileSync(from);
+        entries = zip.Reader(data).toObject();
+
+        if (!fs.existsSync(to)) {
+            wrench.mkdirSyncRecursive(to, "0755");
+        }
+
+        for (p in entries) {
+            if (p.indexOf("__MACOSX") >= 0) {
+                continue;
+            }
+
+            if (p.split("/").length > 1) {
+                parent = p.split("/").slice(0, -1).join("/");
+                wrench.mkdirSyncRecursive(to + "/" + parent, "0755");
+            }
+
+            fs.writeFileSync(to + "/" + p, entries[p]);
+        }
+    } else {
+        throw localize.translate("EXCEPTION_WIDGET_ARCHIVE_NOT_FOUND", from);
+    }
+}
+
+function copyDirContents(from, to) {
+    var files = wrench.readdirSyncRecursive(from),
+        bbwpignore,
+        bbwpignoreFile = path.join(from, conf.BBWP_IGNORE_FILENAME),
+        toBeIgnored = [];
+
+    if (fs.existsSync(bbwpignoreFile)) {
+        bbwpignore = new BBWPignore(bbwpignoreFile, files);
+
+        bbwpignore.matchedFiles.forEach(function (i) {
+            toBeIgnored.push(from + "/" + i);
+        });
+        toBeIgnored.push(from + "/" + conf.BBWP_IGNORE_FILENAME); //add the .bbwpignore file to the ignore list
+    }
+    wrench.copyDirSyncRecursive(from, to, {preserve: true}, function (file) {
+        return toBeIgnored.indexOf(file) === -1;
+    });
+}
+
+function prepare(session) {
+    var conf = session.conf,
+        dest = session.sourcePaths;
+
+    if (fs.existsSync(session.sourceDir)) {
+        wrench.rmdirSyncRecursive(session.sourceDir);
+    }
+
+    // unzip archive
+    if (fs.existsSync(session.archivePath)) {
+        if (session.archivePath.toLowerCase().match("[.]zip$")) {
+            unzip(session.archivePath, session.sourceDir);
+        } else {
+            copyDirContents(session.archivePath, session.sourceDir);
+        }
+    } else {
+        throw localize.translate("EXCEPTION_INVALID_ARCHIVE_PATH", session.archivePath);
+    }
+}
+
+
+function getModulesArray(dest, files, baseDir) {
+    var modulesList = [],
+        EXCLUDE_FILES = ["client.js", "manifest.json"];
+
+    function isExcluded(file) {
+        return EXCLUDE_FILES.some(function (element) {
+            return path.basename(file) === element;
+        });
+    }
+
+    files.forEach(function (file) {
+        file = path.resolve(baseDir, file);
+
+        if (!fs.statSync(file).isDirectory()) {
+            if (baseDir !== dest.EXT || !isExcluded(file)) {
+                modulesList.push({name: path.relative(path.normalize(dest.CHROME), file).replace(/\\/g, "/"), file: file});
+            }
+        }
+    });
+
+    return modulesList;
+}
+
+function generateFrameworkModulesJS(session) {
+    var dest = session.sourcePaths,
+        modulesList = [],
+        modulesStr = "(function () { ",
+        frameworkModulesStr = "window.frameworkModules = [",
+        libFiles = wrench.readdirSyncRecursive(dest.LIB),
+        extFiles,
+        extModules;
+
+    modulesList = modulesList.concat(getModulesArray(dest, libFiles, dest.LIB));
+
+    if (fs.existsSync(dest.EXT)) {
+        extFiles = wrench.readdirSyncRecursive(dest.EXT);
+        extModules = getModulesArray(dest, extFiles, dest.EXT);
+        modulesList = modulesList.concat(extModules);
+    }
+
+    modulesList.forEach(function (module, index) {
+        modulesStr += "define('" + module.name + "', function (require, exports, module) {\n" +
+                      fs.readFileSync(module.file, "utf-8") + "\n" +
+                      "});\n";
+        frameworkModulesStr += "'" + module.name + "'" +  (index !== modulesList.length-1 ? ", " : "");
+    });
+
+    modulesStr += "}());";
+    frameworkModulesStr += "];\n";
+    fs.writeFileSync(path.normalize(dest.CHROME + "/frameworkModules.js"), frameworkModulesStr + modulesStr);
+}
+
+function copyNative(session, target) {
+    var src = path.normalize(session.conf.NATIVE + "/" + target),
+        dest = path.normalize(session.sourceDir);
+
+    copyDirContents(src, dest);
+}
+
+function copyWebworks(session) {
+    var srcPath = path.normalize(session.conf.PROJECT_ROOT + "/lib"),
+        dest = path.normalize(session.sourceDir),
+        srcFiles;
+
+    srcFiles = packagerUtils.listFiles(srcPath, function (file) {
+        return CORDOVA_JS_REGEX.test(file);
+    });
+
+    if (srcFiles.length === 1) {
+        packagerUtils.copyFile(srcFiles[0], dest);
+
+        //Rename file to webworks.js
+        fs.renameSync(path.join(dest, path.basename(srcFiles[0])), path.join(dest, "cordova.js"));
+    } else {
+        throw localize.translate("EXCEPTION_CORDOVA_JS_IN_LIB_DIR", srcFiles.length);
+    }
+}
+
+function hasValidExtension(file) {
+    return VALID_EXTENSIONS.some(function (element, index, array) {
+        return path.extname(file) === element;
+    });
+}
+
+function generateUserConfig(session, config) {
+    packagerUtils.writeFile(path.join(session.sourcePaths.LIB, "config"), "user.js", "module.exports = " + JSON.stringify(config, null, "    ") + ";");
+}
+
+module.exports = {
+    unzip: unzip,
+
+    copyNative: copyNative,
+
+    copyWebworks : copyWebworks,
+
+    prepareOutputFiles: prepare,
+
+    generateFrameworkModulesJS: generateFrameworkModulesJS,
+
+    generateUserConfig: generateUserConfig,
+
+    cleanSource: function (session) {
+        if (!session.keepSource) {
+            wrench.rmdirSyncRecursive(session.sourceDir);
+        }
+    },
+
+    copyDirContents: copyDirContents
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/88ad654c/lib/cordova-blackberry/bin/templates/project/cordova/lib/i18n-manager.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/cordova/lib/i18n-manager.js b/lib/cordova-blackberry/bin/templates/project/cordova/lib/i18n-manager.js
new file mode 100644
index 0000000..3aa1645
--- /dev/null
+++ b/lib/cordova-blackberry/bin/templates/project/cordova/lib/i18n-manager.js
@@ -0,0 +1,146 @@
+/*
+ *  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.
+ */
+/*jshint sub:true*/
+var path = require("path"),
+    fs = require("fs"),
+    wrench = require("wrench"),
+    pkgrUtils = require("./packager-utils"),
+    LOCALES_DIR = "locales";
+
+// Given a list of locale files (as follows), based on un-localized splash/icon definition, generate
+// localized splash/icon metadata.
+//
+// zh-hans-cn/a.gif
+// zh-hans-cn/f.gif
+// zh-hans-cn/images/splash-1024x600.png
+// zh-hans-cn/images/splash-600x1024.png
+// zh-hans/a.gif
+// zh-hans/b.gif
+// zh/a.gif
+// zh/b.gif
+// zh/c.gif
+function generateLocalizedMetadataForSplashScreenIcon(config, configKey, xmlObject, xmlObjectKey, localeFiles) {
+    // localeMap looks like this:
+    // {
+    //     "zh-hans-cn": ["a.gif", "f.gif", "images/splash-1024x600.png", "images/splash-600x1024.png"],
+    //     "zh-hans": ["a.gif", "b.gif"],
+    //     "zh": ["a.gif", "b.gif", "c.gif"]
+    // }
+    var localeMap = {};
+
+    if (localeFiles) {
+        localeFiles.forEach(function (path) {
+            var splitted = path.replace(/\.\./g, "").split("/"),
+                locale;
+
+            splitted = splitted.filter(function (element) {
+                return element.length > 0;
+            });
+
+            if (splitted.length > 1) {
+                locale = splitted[0];
+
+                if (!localeMap[locale]) {
+                    localeMap[locale] = [];
+                }
+
+                // remove locale subfolder from path
+                splitted.splice(0, 1);
+                localeMap[locale].push(splitted.join("/"));
+            }
+        });
+    }
+
+    xmlObject[xmlObjectKey] = {};
+    xmlObject[xmlObjectKey]["image"] = [];
+
+    if (config[configKey]) {
+        config[configKey].forEach(function (imgPath) {
+            imgPath = imgPath.replace(/\\/g, "/"); // replace any backslash with forward slash
+
+            Object.getOwnPropertyNames(localeMap).forEach(function (locale) {
+                if (localeMap[locale].indexOf(imgPath) !== -1) {
+                    // localized image found for locale
+                    xmlObject[xmlObjectKey]["image"].push({
+                        text: {
+                            _attr: {
+                                "xml:lang": locale
+                            },
+                            _value: LOCALES_DIR + "/" + locale + "/" + imgPath
+                        }
+                    });
+                }
+            });
+
+            xmlObject[xmlObjectKey]["image"].push({
+                _value: imgPath
+            });
+        });
+    }
+}
+
+function generateLocalizedText(session, config, xmlObject, key) {
+    var localizedText = config[key],
+        textElements = [],
+        locale;
+
+    for (locale in localizedText) {
+        if (localizedText.hasOwnProperty(locale)) {
+            //Don't add default locale and don't add locale if it already exists
+            if (locale !== 'default' && textElements && textElements.indexOf(locale) === -1) {
+                textElements.push({
+                    _attr: {
+                        "xml:lang": locale
+                    },
+                    _value: localizedText[locale]
+                });
+            }
+        }
+    }
+
+    xmlObject[key] = {
+        _value: localizedText['default'],
+        text: textElements
+    };
+}
+
+function generateLocalizedMetadata(session, config, xmlObject, key) {
+    if (config.icon || config["rim:splash"]) {
+        var localeFiles,
+            normalizedLocaleFiles = [];
+
+        if (fs.existsSync(session.sourceDir + "/" + LOCALES_DIR)) {
+            localeFiles = wrench.readdirSyncRecursive(session.sourceDir + "/" + LOCALES_DIR);
+            if (pkgrUtils.isWindows()) {
+
+                localeFiles.forEach(function (file) {
+                    file = path.relative(path.resolve(session.sourceDir, "locales"), file).replace(/\\/g, "/");
+                    normalizedLocaleFiles.push(file);
+                });
+            } else {
+                normalizedLocaleFiles = localeFiles;
+            }
+        }
+
+        generateLocalizedMetadataForSplashScreenIcon(config, key, xmlObject, key === "rim:splash" ? "splashScreens" : key, normalizedLocaleFiles);
+    }
+}
+
+module.exports = {
+    LOCALES_DIR: LOCALES_DIR,
+    generateLocalizedMetadata: generateLocalizedMetadata,
+    generateLocalizedText: generateLocalizedText
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/88ad654c/lib/cordova-blackberry/bin/templates/project/cordova/lib/localize.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/cordova/lib/localize.js b/lib/cordova-blackberry/bin/templates/project/cordova/lib/localize.js
new file mode 100644
index 0000000..04e89ac
--- /dev/null
+++ b/lib/cordova-blackberry/bin/templates/project/cordova/lib/localize.js
@@ -0,0 +1,207 @@
+/*
+ *  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 Localize = require("localize"),
+    loc = new Localize({
+        "EXCEPTION_NATIVEPACKAGER": {
+            "en": "Native Packager exception occurred"
+        },
+        "EXCEPTION_WIDGET_ARCHIVE_NOT_FOUND": {
+            "en": "Failed to find WebWorks archive: $[1]"
+        },
+        "EXCEPTION_MISSING_SIGNING_KEY_FILE": {
+            "en": "Cannot sign application - failed to find signing key file: $[1]"
+        },
+        "WARNING_MISSING_SIGNING_KEY_FILE": {
+            "en": "Build ID set in config.xml [version], but signing key file was not found: $[1]"
+        },
+        "EXCEPTION_MISSING_SIGNING_PASSWORD": {
+            "en": "Cannot sign application - No signing password provided [-g]"
+        },
+        "WARNING_SIGNING_PASSWORD_EXPECTED": {
+            "en": "Build ID set in config.xml [version], but no signing password was provided [-g]. Bar will be unsigned"
+        },
+        "EXCEPTION_MISSING_SIGNING_BUILDID": {
+            "en": "Cannot sign application - No buildId provided [--buildId]"
+        },
+        "EXCEPTION_DEBUG_TOKEN_NOT_FOUND": {
+            "en": "Failed to find debug token"
+        },
+        "EXCEPTION_DEBUG_TOKEN_WRONG_FILE_EXTENSION": {
+            "en": "Specified debug token not a .bar extension"
+        },
+        "PROGRESS_SESSION_CONFIGXML": {
+            "en": "Parsing config.xml"
+        },
+        "PROGRESS_FILE_POPULATING_SOURCE": {
+            "en": "Populating application source"
+        },
+        "PROGRESS_GEN_OUTPUT": {
+            "en": "Generating output files"
+        },
+        "PROGRESS_PACKAGING": {
+            "en": "Packaging the BAR file"
+        },
+        "PROGRESS_COMPLETE": {
+            "en": "BAR packaging complete"
+        },
+        "EXCEPTION_PARSING_XML": {
+            "en": "An error has occurred parsing the config.xml. Please ensure that it is syntactically correct"
+        },
+        "EXCEPTION_INVALID_VERSION": {
+            "en": "Please enter a valid application version"
+        },
+        "EXCEPTION_INVALID_NAME": {
+            "en": "Please enter a valid application name"
+        },
+        "EXCEPTION_INVALID_AUTHOR": {
+            "en": "Please enter an author for the application"
+        },
+        "EXCEPTION_INVALID_ID": {
+            "en": "Please enter an application id"
+        },
+        "EXCEPTION_INVALID_CONTENT": {
+            "en": "Invalid config.xml - failed to parse the <content> element(Invalid source or the source is not specified.)"
+        },
+        "EXCEPTION_INVALID_FEATURE_ID": {
+            "en": "Invalid <feature> element - failed to find the id attribute"
+        },
+        "EXCEPTION_BUFFER_ERROR": {
+            "en": "ERROR in bufferToString(): Buffer length must be even"
+        },
+        "EXCEPTION_FEATURE_DEFINED_WITH_WILDCARD_ACCESS_URI": {
+            "en": "Invalid config.xml - no <feature> tags are allowed for this <access> element"
+        },
+        "EXCEPTION_INVALID_ACCESS_URI_NO_PROTOCOL": {
+            "en": "Invalid URI attribute in the access element - protocol required($[1])"
+        },
+        "EXCEPTION_INVALID_ACCESS_URI_NO_URN": {
+            "en": "Failed to parse the URI attribute in the access element($[1])"
+        },
+        "EXCEPTION_CMDLINE_ARG_INVALID": {
+            "en": "Invalid command line argument \"$[1]\""
+        },
+        "EXCEPTION_INVOKE_TARGET_INVALID_ID": {
+            "en": "Each rim:invoke-target element must specify a valid id attribute"
+        },
+        "EXCEPTION_INVOKE_TARGET_INVALID_TYPE": {
+            "en": "rim:invoke-target element must be specified and cannot be empty"
+        },
+        "EXCEPTION_INVOKE_TARGET_ACTION_INVALID": {
+            "en": "Each filter element must specify at least one valid action"
+        },
+        "EXCEPTION_INVOKE_TARGET_MIME_TYPE_INVALID": {
+            "en": "Each filter element must specify at least one valid mime-type"
+        },
+        "EXCEPTION_INVOKE_TARGET_FILTER_PROPERTY_INVALID": {
+            "en": "At least one property element in an invoke filter is invalid"
+        },
+        "EXCEPTION_INVALID_ICON_SRC": {
+            "en": "Icon src cannot be empty"
+        },
+        "EXCEPTION_INVALID_SPLASH_SRC": {
+            "en": "Splash src cannot be empty"
+        },
+        "EXCEPTION_INVALID_ICON_SRC_LOCALES": {
+            "en": "Icon src should not point to files under \"locales\" folder, bbwp will perform folder-based localization"
+        },
+        "EXCEPTION_INVALID_SPLASH_SRC_LOCALES": {
+            "en": "Splash src should not point to files under \"locales\" folder, bbwp will perform folder-based localization"
+        },
+        "EXCEPTION_EXTENSION_CIRCULAR_DEPENDENCY": {
+            "en": "Circular dependency detected for extension: \"$[1]\""
+        },
+        "EXCEPTION_EXTENSION_NOT_FOUND": {
+            "en": "Extension \"$[1]\" not found in \"ext\" folder"
+        },
+        "EXCEPTION_PARAMS_FILE_ERROR": {
+            "en": "An error has occurred parsing \"$[1]\""
+        },
+        "EXCEPTION_PARAMS_FILE_NOT_FOUND": {
+            "en": "\"$[1]\" does not exist"
+        },
+        "EXCEPTION_MISSING_TOOLS": {
+            "en": "BBNDK tools could not be found. Please ensure you have installed the BlackBerry Native SDK [http://developer.blackberry.com/native/] and have the PATH configured via bbndk-env script."
+        },
+        "EXCEPTION_INVALID_ORIENTATION_MODE": {
+            "en": "\"$[1]\" is not a valid orientation mode"
+        },
+        "EXCEPTION_EMPTY_ORIENTATION_MODE": {
+            "en": "blackberry.app.orientation parameter \"mode\" missing"
+        },
+        "EXCEPTION_BGCOLOR_INVALID" : {
+            "en": "Background color \"$[1]\" is not a valid number"
+        },
+        "EXCEPTION_CONFIG_NOT_FOUND" : {
+            "en": "No config.xml file was found at the root of the .zip file"
+        },
+        "EXCEPTION_CORDOVA_JS_IN_LIB_DIR" : {
+            "en": "$[1] cordova.js files found in lib"
+        },
+        "WARN_CORDOVA_JS_PACKAGED" : {
+            "en": "cordova.js is now packaged as local:///chrome/cordova.js"
+        },
+        "WARN_WEBPLATFORM_JS_PACKAGED" : {
+            "en": "webplatform.js has been packaged as an alternative to the on device version"
+        },
+        "WARN_WEBPLATFORM_I18N_PACKAGED" : {
+            "en": "i18n.js has been packaged as an alternative to the on device version"
+        },
+        "EXCEPTION_INVALID_ARCHIVE_PATH" : {
+            "en": "An archive or directory does not exist at the path specified: \"$[1]\""
+        },
+        "EXCEPTION_APPDESC_NOT_FOUND" : {
+            "en": "The bar descriptor file does not exist at the path specified: \"$[1]\""
+        },
+        "WARNING_ORIENTATION_DEPRECATED": {
+            "en": "blackberry.app.orientation has been deprecated, please use blackberry.app instead"
+        },
+        "WARNING_WEBSECURITY_DISABLED": {
+            "en": "You have disabled all web security in this WebWorks application"
+        },
+        "PROGRESS_WILL_CREATE_DEBUG_TOKEN": {
+            "en": "Will create debug token"
+        },
+        "PROGRESS_WILL_DEPLOY_DEBUG_TOKEN": {
+            "en": "Will deploy debug token"
+        },
+        "WARN_TARGET_NOT_EXIST": {
+            "en": "The target \"$[1]\" does not exist"
+        },
+        "WARN_IP_NOT_DEFINED": {
+            "en": "IP is not defined in target \"$[1]\""
+        },
+        "WARN_PASSWORD_NOT_DEFINED": {
+            "en": "Password is not defined in target \"$[1]\""
+        },
+        "PROGRESS_DEPLOYING_DEBUG_TOKEN": {
+            "en": "Deploying debug token to target \"$[1]\""
+        },
+        "WARN_NO_DEVICE_PIN_FOUND": {
+            "en": "No device PIN found, will omit debug token generation"
+        },
+        "WARN_NO_SIGNING_PASSWORD_PROVIDED": {
+            "en": "No signing password provided, will omit debug token generation"
+        },
+        "PROGRESS_GENERATING_DEBUG_TOKEN": {
+            "en": "Generating debug token"
+        }
+
+    }, "", ""); // TODO maybe a bug in localize, must set default locale to "" in order get it to work
+
+loc.setLocale("en");
+
+module.exports = loc;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/88ad654c/lib/cordova-blackberry/bin/templates/project/cordova/lib/logger.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/cordova/lib/logger.js b/lib/cordova-blackberry/bin/templates/project/cordova/lib/logger.js
new file mode 100644
index 0000000..6cab576
--- /dev/null
+++ b/lib/cordova-blackberry/bin/templates/project/cordova/lib/logger.js
@@ -0,0 +1,38 @@
+/*
+ *  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 level = 'verbose';
+
+module.exports = {
+    level: function (value) {
+        level = value;
+    },
+    info: function (msg) {
+        if (level === 'verbose') {
+            console.log("[INFO]    " + msg);
+        }
+    },
+    error: function (msg) {
+        console.log("[ERROR]   " + msg);
+    },
+    warn: function (msg) {
+        if (level !== 'error') {
+            console.log("[WARN]    " + msg);
+        }
+    },
+    log: function (msg) {
+        console.log("[BUILD]   " + msg);
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/88ad654c/lib/cordova-blackberry/bin/templates/project/cordova/lib/native-packager.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/cordova/lib/native-packager.js b/lib/cordova-blackberry/bin/templates/project/cordova/lib/native-packager.js
new file mode 100644
index 0000000..d9fe3a2
--- /dev/null
+++ b/lib/cordova-blackberry/bin/templates/project/cordova/lib/native-packager.js
@@ -0,0 +1,288 @@
+/*
+ *  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.
+ */
+/*jshint sub:true*/
+var childProcess = require("child_process"),
+    fs = require("fs"),
+    path = require("path"),
+    util = require("util"),
+    data2xml = require("../third_party/data2xml/data2xml"),
+    wrench = require("wrench"),
+    conf = require("./conf"),
+    logger = require("./logger"),
+    localize = require("./localize"),
+    pkgrUtils = require("./packager-utils"),
+    i18nMgr = require("./i18n-manager"),
+    NL = pkgrUtils.isWindows() ? "\r\n" : "\n";
+
+function generateTabletXMLFile(session, config) {
+    var files = wrench.readdirSyncRecursive(session.sourceDir),
+        xmlObject = {
+            id : config.id,
+            versionNumber : config.version,
+            author : config.author,
+            asset : [{
+                _attr : { entry : 'true', type : 'qnx/elf' },
+                _value : 'wwe'
+            }],
+            entryPointType : {
+                _value : "Qnx/WebKit"
+            },
+            cascadesTheme : {
+                _value : config.theme
+            },
+            initialWindow : {
+                systemChrome : 'none',
+                transparent : 'true',
+                autoOrients : 'true'
+            },
+            env : [{
+                _attr : { value : '2.0.0', var : 'WEBWORKS_VERSION'}
+            }],
+            permission : [{
+                _attr : { system : 'true'},
+                _value : 'run_native'
+            }, {
+                // hardcoded access_internet to ensure user has internet (whitelist takes care of security)
+                _attr : { system : 'false'},
+                _value : 'access_internet'
+            }]
+        };
+
+    // If appdesc is specified, use it as the bar descriptor
+    if (session.appdesc) {
+        pkgrUtils.copyFile(session.appdesc, session.sourceDir);
+        return;
+    }
+
+    //Enable slog2 output if debugging
+    if (session.debug) {
+        xmlObject.env.push({
+            _attr : { value : 'slog2', 'var' : 'CONSOLE_MODE' }
+        });
+    }
+
+    //Write user specified permissions
+    if (config.permissions) {
+        config.permissions.forEach(function (permission) {
+            var permissionAttr,
+                permissionValue;
+
+            if (typeof permission === "string") {
+                //Permission with no attributes
+                permissionValue = permission;
+            } else if (permission["@"] && permission["#"]) {
+                //Permission with attributes
+                permissionAttr = permission["@"];
+                permissionValue = permission["#"];
+            }
+
+            if (permissionValue) {
+                xmlObject.permission.push({
+                    _attr : permissionAttr,
+                    _value : permissionValue
+                });
+            }
+        });
+    }
+
+    i18nMgr.generateLocalizedText(session, config, xmlObject, "name");
+
+    if (config.description) {
+        i18nMgr.generateLocalizedText(session, config, xmlObject, "description");
+    }
+
+    i18nMgr.generateLocalizedMetadata(session, config, xmlObject, "icon");
+    i18nMgr.generateLocalizedMetadata(session, config, xmlObject, "rim:splash");
+
+    if (config["invoke-target"]) {
+        xmlObject["invoke-target"] = [];
+
+        config["invoke-target"].forEach(function (invokeTarget) {
+
+            var xmlInvokeTarget = {
+                "_attr" : { id : invokeTarget["@"]["id"] },
+                "entry-point" : config.name,
+                "type" : invokeTarget["type"]
+            };
+
+            if (invokeTarget["require-source-permissions"]) {
+                xmlInvokeTarget["require-source-permissions"] = {
+                    _value : invokeTarget["require-source-permissions"]
+                };
+            }
+
+            if (invokeTarget.filter) {
+                xmlInvokeTarget.filter = [];
+                invokeTarget.filter.forEach(function (filter) {
+                    var xmlFilter = {
+                        "action" : filter.action,
+                        "mime-type": filter["mime-type"]
+                    };
+
+                    if (filter.property) {
+                        xmlFilter.property = [];
+                        filter.property.forEach(function (property) {
+                            xmlFilter.property.push({
+                                "_attr": { var : property["@"]["var"], value : property["@"].value }
+                            });
+                        });
+                    }
+
+                    xmlInvokeTarget.filter.push(xmlFilter);
+                });
+            }
+
+            xmlObject["invoke-target"].push(xmlInvokeTarget);
+
+        });
+    }
+
+    //buildId
+    if (config.buildId) {
+        xmlObject.buildId = config.buildId;
+    }
+
+    if (files) {
+        files.forEach(function (file) {
+            file = path.resolve(session.sourceDir, file);
+
+            if (file.indexOf(conf.BAR_DESCRIPTOR) < 0 && !fs.statSync(file).isDirectory()) {
+                file = file.replace(/\\/g, "/");
+                file = file.split("src/")[1];
+
+                if (path.extname(file) === ".so") {
+                    xmlObject.asset.push({
+                        _attr : { type : 'qnx/elf' },
+                        _value : file
+                    });
+                } else {
+                    xmlObject.asset.push({
+                        _value : file
+                    });
+                }
+            }
+        });
+    }
+
+    //Add orientation mode
+    if (config.orientation) {
+        xmlObject.initialWindow.aspectRatio = config.orientation;
+    }
+
+    //Add auto orientation
+    xmlObject.initialWindow.autoOrients = config.autoOrientation;
+
+    pkgrUtils.writeFile(session.sourceDir, conf.BAR_DESCRIPTOR, data2xml('qnx', xmlObject));
+}
+
+function generateOptionsFile(session, target, config) {
+    var srcFiles = wrench.readdirSyncRecursive(session.sourceDir),
+        isSigning = session.isSigningRequired(config),
+        optionsStr = "-package" + NL,
+        debugToken,
+        params = session.getParams("blackberry-nativepackager");
+
+    //if -d was provided and we are not signing [-g], set debugToken
+    if (session.debug && !isSigning) {
+        if (path.extname(conf.DEBUG_TOKEN) === ".bar") {
+            if (fs.existsSync(conf.DEBUG_TOKEN)) {
+                debugToken = "-debugToken" + NL;
+                debugToken += conf.DEBUG_TOKEN + NL;
+            }
+            else {
+                logger.warn(localize.translate("EXCEPTION_DEBUG_TOKEN_NOT_FOUND"));
+            }
+        } else {
+            logger.warn(localize.translate("EXCEPTION_DEBUG_TOKEN_WRONG_FILE_EXTENSION"));
+        }
+    }
+
+    if (target === "device" && isSigning) {
+        optionsStr += "-buildId" + NL;
+        optionsStr += config.buildId + NL;
+    } else if (session.debug) {
+        //DebugToken params
+        optionsStr += "-devMode" + NL;
+        optionsStr += (debugToken ? debugToken : "");
+    }
+
+    if (params) {
+        Object.getOwnPropertyNames(params).forEach(function (p) {
+            optionsStr += p + NL;
+
+            if (params[p]) {
+                optionsStr += params[p] + NL;
+            }
+        });
+    }
+
+    optionsStr += path.resolve(util.format(session.barPath, target)) + NL;
+
+    //to supoprt splash screens/icons for multiple resolutions/devices
+    optionsStr += "-barVersion" + NL;
+    optionsStr += "1.5" + NL;
+
+    optionsStr += "-C" + NL;
+    optionsStr += session.sourceDir + NL;
+    optionsStr += conf.BAR_DESCRIPTOR + NL;
+
+    srcFiles.forEach(function (file) {
+        file = path.resolve(session.sourceDir, file);
+
+        if (file.indexOf(conf.BAR_DESCRIPTOR) < 0 && !fs.statSync(file).isDirectory()) {
+            optionsStr += file + NL;
+        }
+    });
+
+    fs.writeFileSync(path.normalize(session.sourceDir + "/options"), optionsStr);
+}
+
+function execNativePackager(session, callback) {
+    var script = "/bin/blackberry-nativepackager",
+        cwd = session.sourceDir,
+        nativePkgr;
+
+    if (pkgrUtils.isWindows()) {
+        script += ".bat";
+    }
+
+    if (fs.existsSync(conf.DEPENDENCIES_TOOLS)) {
+        nativePkgr = childProcess.spawn(path.normalize(conf.DEPENDENCIES_TOOLS + script), ["@options"], {
+            "cwd": cwd,
+            "env": process.env
+        });
+
+        nativePkgr.stdout.on("data", pkgrUtils.handleProcessOutput);
+
+        nativePkgr.stderr.on("data", pkgrUtils.handleProcessOutput);
+
+        nativePkgr.on("exit", function (code) {
+            if (callback && typeof callback === "function") {
+                callback(code);
+            }
+        });
+    } else {
+        throw localize.translate("EXCEPTION_MISSING_TOOLS");
+    }
+}
+
+module.exports = {
+    exec: function (session, target, config, callback) {
+        generateOptionsFile(session, target, config);
+        generateTabletXMLFile(session, config);
+        execNativePackager(session, callback);
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/88ad654c/lib/cordova-blackberry/bin/templates/project/cordova/lib/packager-utils.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/cordova/lib/packager-utils.js b/lib/cordova-blackberry/bin/templates/project/cordova/lib/packager-utils.js
new file mode 100644
index 0000000..09465e8
--- /dev/null
+++ b/lib/cordova-blackberry/bin/templates/project/cordova/lib/packager-utils.js
@@ -0,0 +1,176 @@
+/*
+ *  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 fs = require('fs'),
+    path = require('path'),
+    wrench = require('wrench'),
+    localize = require("./localize"),
+    logger = require("./logger"),
+    os = require('os'),
+    _self;
+
+function swapBytes(buffer) {
+    var l = buffer.length,
+        i,
+        a;
+
+    if (l % 2 === 0x01) {
+        throw localize.translate("EXCEPTION_BUFFER_ERROR");
+    }
+
+    for (i = 0; i < l; i += 2) {
+        a = buffer[i];
+        buffer[i] = buffer[i + 1];
+        buffer[i + 1] = a;
+    }
+
+    return buffer;
+}
+
+_self = {
+    writeFile: function (fileLocation, fileName, fileData) {
+        //If directory does not exist, create it.
+        if (!fs.existsSync(fileLocation)) {
+            wrench.mkdirSyncRecursive(fileLocation, "0755");
+        }
+
+        fs.writeFileSync(path.join(fileLocation, fileName), fileData);
+    },
+    
+    copyFile: function (srcFile, destDir, baseDir) {
+        var filename = path.basename(srcFile),
+            fileBuffer = fs.readFileSync(srcFile),
+            fileLocation;
+        
+        //if a base directory was provided, determine
+        //folder structure from the relative path of the base folder
+        if (baseDir && srcFile.indexOf(baseDir) === 0) {
+            fileLocation = srcFile.replace(baseDir, destDir);
+            wrench.mkdirSyncRecursive(path.dirname(fileLocation), "0755");
+            fs.writeFileSync(fileLocation, fileBuffer);
+        } else {
+            fs.writeFileSync(path.join(destDir, filename), fileBuffer);
+        }
+    },
+    
+    listFiles: function (directory, filter) {
+        var files = wrench.readdirSyncRecursive(directory),
+            filteredFiles = [];
+        
+        files.forEach(function (file) {
+            //On mac wrench.readdirSyncRecursive does not return absolute paths, so resolve one.
+            file = path.resolve(directory, file);
+        
+            if (filter(file)) {
+                filteredFiles.push(file);
+            }
+        });
+        
+        return filteredFiles;
+    },
+
+    isWindows: function () {
+        return os.type().toLowerCase().indexOf("windows") >= 0;
+    },
+    
+    isArray: function (obj) {
+        return obj.constructor.toString().indexOf("Array") !== -1;
+    },
+
+    isEmpty : function (obj) {
+        for (var prop in obj) {
+            if (obj.hasOwnProperty(prop))
+                return false;
+        }
+        return true;
+    },
+    
+    toBoolean: function (myString, defaultVal) {
+        // if defaultVal is not passed, default value is undefined
+        return myString === "true" ? true : myString === "false" ? false : defaultVal;
+    },
+
+    parseUri : function (str) {
+        var i, uri = {},
+            key = [ "source", "scheme", "authority", "userInfo", "user", "password", "host", "port", "relative", "path", "directory", "file", "query", "anchor" ],
+            matcher = /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(str);
+
+        for (i = key.length - 1; i >= 0; i--) {
+            uri[key[i]] = matcher[i] || "";
+        }
+
+        return uri;
+    },
+
+    // uri - output from parseUri
+    isAbsoluteURI : function (uri) {
+        if (uri && uri.source) {
+            return uri.relative !== uri.source;
+        }
+
+        return false;
+    },
+
+    isLocalURI : function (uri) {
+        return uri && uri.scheme && uri.scheme.toLowerCase() === "local";
+    },
+
+    // Convert node.js Buffer data (encoded) to String
+    bufferToString : function (data) {
+        var s = "";
+        if (Buffer.isBuffer(data)) {
+            if (data.length >= 2 && data[0] === 0xFF && data[1] === 0xFE) {
+                s = data.toString("ucs2", 2);
+            } else if (data.length >= 2 && data[0] === 0xFE && data[1] === 0xFF) {
+                swapBytes(data);
+                s = data.toString("ucs2", 2);
+            } else if (data.length >= 3 && data[0] === 0xEF && data[1] === 0xBB && data[2] === 0xBF) {
+                s = data.toString("utf8", 3);
+            } else {
+                s = data.toString("ascii");
+            }
+        }
+
+        return s;
+    },
+
+    // Wrap object property in an Array if the property is defined and it is not an Array
+    wrapPropertyInArray : function (obj, property) {
+        if (obj && obj[property] && !(obj[property] instanceof Array)) {
+            obj[property] = [ obj[property] ];
+        }
+    },
+
+    loadModule: function (path) {
+        return require(path);
+    },
+
+    handleProcessOutput: function (data) {
+        var msg = data.toString().replace(/[\n\r]/g, '');
+
+        if (msg) {
+            if (msg.toLowerCase().indexOf("error:") >= 0) {
+                logger.error(msg);
+            } else if (msg.toLowerCase().indexOf("warn") >= 0) {
+                logger.warn(msg);
+            } else {
+                logger.info(msg);
+            }
+        }
+    }
+};
+
+module.exports = _self;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/88ad654c/lib/cordova-blackberry/bin/templates/project/cordova/lib/packager-validator.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/cordova/lib/packager-validator.js b/lib/cordova-blackberry/bin/templates/project/cordova/lib/packager-validator.js
new file mode 100644
index 0000000..507b9f2
--- /dev/null
+++ b/lib/cordova-blackberry/bin/templates/project/cordova/lib/packager-validator.js
@@ -0,0 +1,110 @@
+/*
+ *  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 check = require('validator').check,
+    sanitize = require('validator').sanitize,
+    localize = require("./localize"),
+    logger = require("./logger"),
+    signingHelper = require("./signing-helper"),
+    path = require("path"),
+    fs = require("fs"),
+    packagerUtils = require("./packager-utils"),
+    CORDOVA_JS_REGEX = /(cordova-.+js)|cordova\.js/,
+    _self;
+
+//NOTE this class is unfinished and is a work in progress
+
+_self = {
+    //TODO create one global validate method that will validate
+    //both the session and configObj?
+    validateSession: function (session, widgetConfig) {
+        //The string checks below is to get around a really weird issue in commander
+        //where sometimes unspecified arguments come in as a function...
+        var keysFound = session.keystore,
+            cskFound = session.keystoreCsk,//barsigner.csk
+            dbFound = session.keystoreDb,//barsigner.db
+            keysPassword = session.storepass && typeof session.storepass === "string",
+            commandLinebuildId = session.buildId && typeof session.buildId === "string",//--buildId
+            buildId = widgetConfig.buildId && typeof widgetConfig.buildId === "string",//Finalized Build ID
+
+            //Constants
+            AUTHOR_P12 = "author.p12",
+            BARSIGNER_CSK = "barsigner.csk",
+            BARSIGNER_DB = "barsigner.db",
+
+            //Logging function
+            signingFileWarn = function (file) {
+                logger.warn(localize.translate("WARNING_MISSING_SIGNING_KEY_FILE", file));
+            },
+            signingFileError = function (file) {
+                throw localize.translate("EXCEPTION_MISSING_SIGNING_KEY_FILE", file);
+            };
+
+        //If -g <password> or --buildId is set, but signing key files are missing, throw an error
+        if (keysPassword || commandLinebuildId) {
+            if (!keysFound) {
+                signingFileError(AUTHOR_P12);
+            } else if (!cskFound) {
+                signingFileError(BARSIGNER_CSK);
+            } else if (!dbFound) {
+                signingFileError(BARSIGNER_DB);
+            }
+
+        //If a buildId exists in config, but no keys were found, throw a warning
+        } else if (buildId) {
+            if (!keysFound) {
+                signingFileWarn(AUTHOR_P12);
+            } else if (!cskFound) {
+                signingFileWarn(BARSIGNER_CSK);
+            } else if (!dbFound) {
+                signingFileWarn(BARSIGNER_DB);
+            }
+        }
+
+        //if -g was provided with NO build id, throw error
+        if (keysPassword && !buildId) {
+            throw localize.translate("EXCEPTION_MISSING_SIGNING_BUILDID");
+        }
+
+        if (commandLinebuildId && !keysPassword) {
+            //if --buildId was provided with NO password, throw error
+            throw localize.translate("EXCEPTION_MISSING_SIGNING_PASSWORD");
+        } else if (buildId && !keysPassword) {
+            //if a buildId was provided in config.xml with NO password, throw warning
+            logger.warn(localize.translate("WARNING_SIGNING_PASSWORD_EXPECTED"));
+        }
+
+        //if --appdesc was provided, but the file is not existing, throw an error
+        if (session.appdesc && !fs.existsSync(session.appdesc)) {
+            throw localize.translate("EXCEPTION_APPDESC_NOT_FOUND", session.appdesc);
+        }
+    },
+
+    //Validation for configObj, iterates through whitelisted features in configObj to remove any non-existing APIs
+    validateConfig: function (session, configObj) {
+        //if packageCordovaJs was set, test for existing cordova.js files
+        if (configObj.packageCordovaJs) {
+            cordovaJsFiles = packagerUtils.listFiles(session.sourceDir, function (file) {
+                return CORDOVA_JS_REGEX.test(file);
+            });
+            if (cordovaJsFiles.length > 0) {
+                logger.warn(localize.translate("WARN_CORDOVA_JS_PACKAGED"));
+            }
+        }
+
+    }
+};
+
+module.exports = _self;

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/88ad654c/lib/cordova-blackberry/bin/templates/project/cordova/lib/packager.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/cordova/lib/packager.js b/lib/cordova-blackberry/bin/templates/project/cordova/lib/packager.js
new file mode 100644
index 0000000..01541ac
--- /dev/null
+++ b/lib/cordova-blackberry/bin/templates/project/cordova/lib/packager.js
@@ -0,0 +1,73 @@
+/*
+ *  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.
+ */
+
+require('./../third_party/wrench/wrench');
+
+var path = require("path"),
+    wrench = require("wrench"),
+    cmdline = require("./cmdline"),
+    logger = require("./logger"),
+    fileManager = require("./file-manager"),
+    localize = require("./localize"),
+    configParser = require("./config-parser"),
+    packagerUtils = require("./packager-utils"),
+    packagerValidator = require("./packager-validator"),
+    barBuilder = require("./bar-builder"),
+    session;
+
+module.exports = {
+    start: function(callback) {
+        try {
+            cmdline.parse(process.argv);
+            session = require("./session").initialize(cmdline.commander);
+
+            //prepare files for webworks archiving
+            logger.log(localize.translate("PROGRESS_FILE_POPULATING_SOURCE"));
+            fileManager.prepareOutputFiles(session);
+
+            //parse config.xml
+            logger.log(localize.translate("PROGRESS_SESSION_CONFIGXML"));
+            configParser.parse(path.join(session.sourceDir, "config.xml"), session, function (configObj) {
+                //validate session Object
+                packagerValidator.validateSession(session, configObj);
+                //validage configuration object
+                packagerValidator.validateConfig(session, configObj);
+
+                //generate user.js
+                logger.log(localize.translate("PROGRESS_GEN_OUTPUT"));
+                //Adding debuEnabled property to user.js. Framework will enable/disable WebInspector based on that variable.
+                configObj.debugEnabled = session.debug;
+
+                barBuilder.build(session, configObj, function (code) {
+                    fileManager.cleanSource(session);
+
+                    if (code === 0) {
+                        logger.log(localize.translate("PROGRESS_COMPLETE"));
+
+                        //call packager callback
+                        callback();
+                    }
+                });
+            });
+        } catch (e) {
+            try {
+                fileManager.cleanSource(session);
+            } catch (ex) {}
+
+            logger.error(e);
+        }
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/88ad654c/lib/cordova-blackberry/bin/templates/project/cordova/lib/plugin.js
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/bin/templates/project/cordova/lib/plugin.js b/lib/cordova-blackberry/bin/templates/project/cordova/lib/plugin.js
new file mode 100644
index 0000000..1f11481
--- /dev/null
+++ b/lib/cordova-blackberry/bin/templates/project/cordova/lib/plugin.js
@@ -0,0 +1,197 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+var path = require("path"),
+    shell = require('shelljs'),
+    wrench = require("wrench"),
+    fs = require('fs'),
+    et   = require('elementtree'),
+    PROJECT_ROOT = path.join(__dirname, "..", ".."),
+    PLUGMAN = path.join(PROJECT_ROOT, "cordova", "node_modules", "plugman", "main.js"),
+    GLOBAL_PLUGIN_PATH = require(path.join(PROJECT_ROOT, "project.json")).globalFetchDir,
+    LOCAL_PLUGIN_PATH = path.join(PROJECT_ROOT, "plugins"),
+    argumentor = {
+        action : process.argv[2],
+        plugin: process.argv[3],
+        args: [],
+        reset: function () {
+            this.args = [];
+            return argumentor;
+        },
+        setAction: function () {
+            this.args.push("--" + this.action);
+            return argumentor;
+        },
+        setPlatform: function () {
+            this.args.push("--platform");
+            this.args.push("blackberry10");
+            return argumentor;
+        },
+        setProject: function () {
+            this.args.push("--project");
+            this.args.push(PROJECT_ROOT);
+            return argumentor;
+        },
+        setPlugin: function () {
+            var pluginWithoutTrailingSlash = this.plugin.charAt(this.plugin.length - 1) === "/" ? this.plugin.slice(0, -1) : this.plugin;
+            this.args.push("--plugin");
+            this.args.push(pluginWithoutTrailingSlash);
+            return argumentor;
+        },
+        setPluginsDir: function (isGlobal) {
+            this.args.push("--plugins_dir");
+            if (isGlobal) {
+                this.args.push(GLOBAL_PLUGIN_PATH);
+            } else {
+                this.args.push(LOCAL_PLUGIN_PATH);
+            }
+            return argumentor;
+        },
+        run: function () {
+            var cmd = "";           
+            if (require('os').type().toLowerCase().indexOf("windows") >= 0) {
+                cmd += "@node.exe ";
+            }
+            cmd += PLUGMAN + " " + this.args.join(" ");
+            return shell.exec(cmd, {silent: false});
+        }
+    },
+    plugmanInterface= {
+        "uninstall": function (plugin) {
+                if (plugin) {
+                    argumentor.plugin = plugin;
+                }
+                argumentor.action = "uninstall";
+                argumentor.reset().setAction().setPlatform().setProject().setPlugin().setPluginsDir().run();
+            },
+        "install": function (plugin) {
+                if (plugin) {
+                    argumentor.plugin = plugin;
+                }
+                argumentor.reset().setPlatform().setProject().setPlugin().setPluginsDir().run();
+            }
+    };
+
+function getPluginId(pluginXMLPath) {
+    var pluginEt = new et.ElementTree(et.XML(fs.readFileSync(pluginXMLPath, "utf-8")));
+    return pluginEt._root.attrib.id;
+}
+
+function addPlugin (pluginPath) {
+    var plugin = pluginPath || argumentor.plugin,
+        pluginDirs = [],
+        allFiles;
+
+    //Check if the path they sent in exists
+    if (!fs.existsSync(plugin) ) {
+        //Check if the plugin has been fetched globally
+        plugin = path.resolve(GLOBAL_PLUGIN_PATH, plugin);
+        if (!fs.existsSync(plugin)) {
+            console.log("Input ", pluginPath || argumentor.plugin, " cannot be resolved as a plugin");
+            process.exit(1);
+        }
+    }
+
+    allFiles = wrench.readdirSyncRecursive(plugin);
+    allFiles.forEach(function (file) {
+        var fullPath = path.resolve(plugin, file);
+
+        if (path.basename(file) === "plugin.xml") {
+            pluginDirs.push(path.dirname(fullPath));
+        }
+    });
+
+    if (!pluginDirs.length) {
+        console.log("No plugins could be found given the input " + pluginPath || argumentor.plugin);
+        process.exit(1);
+    } else {
+        pluginDirs.forEach(function (pluginDir) {
+            plugmanInterface.install(pluginDir);
+        });
+    }
+}
+
+function removePlugin (pluginPath) {
+    var plugin = pluginPath || argumentor.plugin,
+        pluginIds = [],
+        allFiles;
+
+    //Check if the path they send in exists
+    if (!fs.existsSync(plugin) ) {
+        //Check if it is the folder name of an installed plugin
+        plugin = path.resolve(LOCAL_PLUGIN_PATH, plugin);
+        if (!fs.existsSync(plugin)) {
+            //Assume that this is a plugin id and continue
+            plugin = pluginPath || argumentor.plugin;
+        }
+    }
+
+    allFiles = wrench.readdirSyncRecursive(plugin);
+    allFiles.forEach(function (file) {
+        var fullPath = path.resolve(plugin, file),
+            pluginEt;
+
+        if (path.basename(file) === "plugin.xml") {
+            pluginIds.push(getPluginId(fullPath));
+        }
+    });
+
+    pluginIds.forEach(function (pluginId) {
+        plugmanInterface.uninstall(pluginId);
+    });
+
+}
+
+function listPlugins () {
+    fs.readdirSync(LOCAL_PLUGIN_PATH).forEach(function (pluginName) {
+        //TODO: Parse the plugin.xml and get any extra information ie description
+        console.log(pluginName);
+    });
+}
+
+function listHelp () {
+    console.log("\nUsage:");
+    console.log("add <plugin_dir> Adds all plugins contained in the given directory");
+    console.log("rm <plugin_name> [<plugin_name>] Removes all of the listed plugins");
+    console.log("ls Lists all of the currently installed plugins");
+}
+
+function cliEntry () {
+    switch (argumentor.action) {
+        case "add":
+            addPlugin();
+            break;
+        case "rm":
+            removePlugin();
+            break;
+        case "ls":
+            listPlugins();
+            break;
+        default:
+            listHelp();
+    }
+}
+
+module.exports = {
+    add: addPlugin,
+    rm: removePlugin,
+    ls: listPlugins,
+    help: listHelp,
+    cli: cliEntry
+};