You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by bh...@apache.org on 2014/03/27 16:08:28 UTC

[14/51] [partial] CB-6346 - Add node_modules to source control

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/localize/README.md
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/localize/README.md b/blackberry10/node_modules/localize/README.md
new file mode 100644
index 0000000..54f52ba
--- /dev/null
+++ b/blackberry10/node_modules/localize/README.md
@@ -0,0 +1,267 @@
+# The *node-localize* library
+provides a [GNU gettext](http://www.gnu.org/s/gettext/)-inspired (but not conformant) translation utility for [Node.js](http://nodejs.org) that tries to avoid some of the limitations of the ``sprintf``-bound ``gettext`` (such as translation string parameters being in a fixed order in all translation results) and "fit in" better than a straight port.
+
+## Installation
+
+If you have [npm](http://npmjs.org), just type:
+
+```sh
+npm install localize
+```
+
+## Usage
+
+``node-localize`` returns an object constructor so multiple simultaneous localization objects may be in use at once (though most cases will probably be a singleton instantiation). The only required parameter on initialization is a ``translations`` object, using the following structure:
+
+```js
+var Localize = require('localize');
+
+var myLocalize = new Localize({
+    "Testing...": {
+        "es": "Pruebas...",
+        "sr": "тестирање..."
+    },
+    "Substitution: $[1]": {
+        "es": "Sustitución: $[1]",
+        "sr": "замена: $[1]"
+    }
+});
+
+console.log(myLocalize.translate("Testing...")); // Testing...
+console.log(myLocalize.translate("Substitution: $[1]", 5)); // Substitution: 5
+
+myLocalize.setLocale("es");
+console.log(myLocalize.translate("Testing...")); // Pruebas...
+
+myLocalize.setLocale("sr");
+console.log(myLocalize.translate("Substitution: $[1]", 5)); // замена: 5
+```
+
+``node-localize`` objects can also be passed a string indicating the directory a ``translations.json`` file can be found. This directory is searched recursively for all ``translations.json`` files in all subdirectories, and their contents combined together, so you can organize your translations as you wish.
+
+The directory is also searched recursively for directories named ``translations``. These directories are checked for special text files of the form ``varname.txt``, ``varname.es.txt``, ``varname.sr.txt``, etc. The text in ``varname.txt`` is treated as the default language of the application and the ``varname.xx.txt`` are treated as translations of the text. A special ``strings`` object is created where the ``varname`` becomes a property of that object and the default language text is the value of the property. So you can also do the following:
+
+```js
+var Localize = require('localize');
+
+var myLocalize = new Localize('./path/to/text/files/');
+
+console.log(myLocalize.translate(myLocalize.strings.reallyLongText); // The contents of ./path/to/text/files/translations/reallyLongText.txt, if it exists
+
+myLocalize.setLocale("es");
+console.log(myLocalize.translate(myLocalize.strings.reallyLongText); // The contents of ./path/to/text/files/translations/reallyLongText.es.txt, if it exists
+```
+
+## Dates
+
+Because date formats differ so wildly in different languages and these differences cannot be solved via simple substitution, there is also a ``localDate`` method for translating these values.
+
+```js
+var theDate = new Date("4-Jul-1776");
+var dateLocalize = new Localize("./translations");
+dateLocalize.loadDateFormats({
+	"es": {
+		dayNames: [
+			'Dom', 'Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb',
+			'Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'
+		],
+		monthNames: [
+			'Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic',
+			'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'
+		],
+		masks: {
+			"default": "dddd, d 'de' mmmm yyyy"
+		}
+	}
+});
+
+console.log(dateLocalize.localDate(theDate)); // Thu Jul 04 1776 00:00:00
+console.log(dateLocalize.localDate(theDate, "fullDate")); // Thursday, July 4, 1776
+console.log(dateLocalize.localDate(theDate, "mm/dd/yyyy")); // 07/04/1776
+
+dateLocalize.setLocale("es");
+console.log(dateLocalize.localDate(theDate)); // Jueves, 4 de Julio 1776
+```
+
+The date formatting rules and configuration have been taken from [node-dateformat](https://github.com/felixge/node-dateformat), which has been extended to support multiple simultaneous locales and subsumed into ``node-localize``.
+
+## Complete API
+
+```js
+var myLocalize = new Localize(translationsObjOrStr, dateFormatObj, defaultLocaleStr);
+// translationsObjOrStr: a conformant translations object or a string indicating
+//     the directory where one or more conformant translations.json files are stored
+// dateFormatObj: a conformant date format object, containing one or more locales
+//     if not specified, will auto-generate an 'en' locale; if initially specified,
+//     will *overwrite* this auto-generated locale object
+// defaultLocale: the locale of all keys in the translations object. Defaults to 'en'
+```
+
+```js
+myLocalize.setLocale(localeStr);
+// localeStr: a locale string to switch to
+```
+
+```js
+myLocalize.loadTranslations(translationsObjOrStr);
+// translationsObjOrStr: a conformant translations object or a string indicating
+//     the directory where one or more conformant translations.json files are stored
+//     Multiple calls to loadTranslations *appends* the keys to the translations
+//     object in memory (overwriting duplicate keys).
+```
+
+```js
+myLocalize.clearTranslations();
+// Wipes out the translations object entirely (if a clean reload is desired)
+```
+
+```js
+myLocalize.throwOnMissingTranslation(throwBool);
+// throwBool: Boolean indicating whether or not missing translations should
+//     throw an error or be silently ignored and the text stay in the default
+//     locale. Useful for development to turn off.
+```
+
+```js
+myLocalize.translate(translateStr, arg1, arg2, ...);
+// translateStr: The string to be translated and optionally perform a
+//     substitution of specified args into. Arguments are specified in a RegExp
+//     style by number starting with 1 (it is the first argument that can be
+//     used and also is the arguments[1] value...), while using a jQuery-style
+//     demarcation of $[x], where x is the argument number.
+```
+
+```js
+myLocalize.loadDateFormats(dateFormatObj);
+// dateFormatObj: a conformant date format object, containing one or more locales
+//     Specified locales are appended to the internal object just like
+//     loadTranslations.
+```
+
+```js
+myLocalize.clearDateFormats();
+// Resets the date formats object to just the 'en' locale.
+```
+
+```js
+myLocalize.localDate(dateObjOrStr, maskStr, utcBool)
+// dateObjOrStr: the date object or string to format as desired in the current
+//     locale.
+// maskStr: the predefined mask to use, or a custom mask.
+// utcBool: a boolean indicating whether the timezone should be local or UTC
+```
+
+```js
+myLocalize.strings
+// Object of key-value pairs defined by files in ``translations`` directories
+// Key is the filename (sans extension) and value is the default language
+// text. Useful for translating very large blocks of text that shouldn't really
+// exist in code.
+```
+
+## _xlocalize_ CLI Utility
+
+Starting at version 0.2.0, ``node-localize``, when installed via NPM, adds an ``xlocalize`` utility command to the _PATH_, which allows for automatic construction of ``translations.json`` files (and can be re-run in the future to update existing files without clobbering any current translations present). It's command switches are as follows:
+
+```
+xlocalize USAGE:
+
+-l	Set the default language for the translations.json file(s) (default: en)
+-r	Set xlocalize to generate translations.json files recursively (default)
+-R	Set xlocalize to only generate a translations.json file for the current directory
+-e	Set the file extensions to include for translation (default: html,js)
+-t	Set the languages to translate to (comma separated)
+-h	Show this help message.
+```
+
+For example, to create a ``translations.json`` file in the current directory only that will translate from English to Spanish, Portuguese, Italian, and French for HTML and JS files:
+
+```sh
+xlocalize -R -t es,pt,it,fr
+```
+
+And if a new language, such as Serbian, is to be translated at a later time, you can use the command:
+```sh
+xlocalize -R -t es,pt,it,fr,sr
+```
+
+## [Express](http://expressjs.com) Integration Tips
+
+If your website supports multiple languages (probably why you're using this library!), you'll want to translate the page content for each supported language. The following snippets of code should make it easy to use within Express.
+
+### Middleware to switch locale on request
+
+```js
+app.configure(function() {
+    ...
+    app.use(function(request, response, next) {
+        var lang = request.session.lang || "en";
+        localize.setLocale(lang);
+        next();
+    });
+    ...
+});
+```
+
+I'm assuming you're storing their language preference inside of a session, but the logic can be easily tweaked for however you detect which language to show.
+
+### Export *translate*, *localDate*, and *strings* as static helpers
+
+```js
+app.helpers({
+    ...
+    translate: localize.translate,
+    localDate: localize.localDate,
+    strings: localize.strings
+});
+```
+
+Your controllers shouldn't really even be aware of any localization issues; the views should be doing that, so this ought to be enough configuration within your ``app.js`` file.
+
+### Using *translate*, *localDate*, and *strings* in your views
+
+```html
+<h1>${translate("My Awesome Webpage")}</h1>
+
+<h2>${translate("By: $[1]", webpageAuthor)}</h2>
+
+<h3>${translate("Published: $[1]", localDate(publicationDate))}</h3>
+
+{{if translate(strings.reallyLongPost) == strings.reallyLongPost}}
+<strong>${translate("Warning: The following content is in English.")}</strong>
+{{/if}}
+
+{{html translate(strings.reallyLongPost)}}
+```
+
+I'm using [jQuery Templates for Express](https://github.com/kof/node-jqtpl) here, but it should be easy to translate to whatever templating language you prefer.
+
+## Planned Features
+
+* Browser compatibility (use same functions for client-side jQuery Templates, for instance)
+* Optional Country Code support (that falls back to baseline language translation if a specific country code is missing) for regional language differences
+* Numeric localization (1,234,567.89 versus 1.234.567,89 versus 1 234 567,89 versus [Japanese Numerals](http://en.wikipedia.org/wiki/Japanese_numerals) [no idea how to handle that one at the moment])
+* Currency localization; not just representing $100.00 versus 100,00$, but perhaps hooking into currency conversion, as well.
+* Pluralization; one area gettext still beats node-localize is the ability to pluralize words correctly when given the number to pluralize against.
+
+## License (MIT)
+
+Copyright (C) 2011 by Agrosica, Inc, David Ellis, Felix Geisendörfer, Steven Levithan, Scott Trenda, Kris Kowal, Jerry Jalava, Clint Andrew Hall.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/localize/bin/translations.json
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/localize/bin/translations.json b/blackberry10/node_modules/localize/bin/translations.json
new file mode 100644
index 0000000..a4d2575
--- /dev/null
+++ b/blackberry10/node_modules/localize/bin/translations.json
@@ -0,0 +1,6 @@
+{
+	"MISSING TRANSLATION": {
+	},
+	"FOUND VARIABLE INPUT $[1]": {
+	}
+}

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/localize/bin/xlocalize.js
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/localize/bin/xlocalize.js b/blackberry10/node_modules/localize/bin/xlocalize.js
new file mode 100755
index 0000000..d34df65
--- /dev/null
+++ b/blackberry10/node_modules/localize/bin/xlocalize.js
@@ -0,0 +1,139 @@
+#!/usr/bin/node
+
+// Load required modules
+var fs = require('fs');
+var path = require('path');
+
+// Use localize for internal localizations
+var localize = new require('localize')(__dirname);
+localize.throwOnMissingTranslation(false);
+var translate = localize.translate;
+
+// Defaults for ``xlocalize``
+var defaultLang = "en";
+var recurse = true;
+var extensions = ['html', 'js'];
+var outLangs = [];
+
+// Load arguments
+for(var i = 0; i < process.argv.length; i++) {
+	switch(process.argv[i]) {
+		case "-l":
+			defaultLang = process.argv[i+1];
+			break;
+		case "-r":
+			recurse = true;
+			break;
+		case "-R":
+			recurse = false;
+			break;
+		case "-e":
+			extensions = process.argv[i+1].split(",");
+			break;
+		case "-t":
+			outLangs = process.argv[i+1].split(",");
+			break;
+		case "-h":
+		case "--help":
+			console.log("xlocalize USAGE:\n");
+			console.log("-l\tSet the default language for the translations.json file(s) (default: en)");
+			console.log("-r\tSet xlocalize to generate translations.json files recursively (default)");
+			console.log("-R\tSet xlocalize to only generate a translations.json file for the current directory");
+			console.log("-e\tSet the file extensions to include for translation (default: html,js)");
+			console.log("-t\tSet the languages to translate to (comma separated)");
+			console.log("-h\tShow this help message.");
+			process.exit();
+		default:
+			break;
+	}
+}
+
+// Set internal localize object to use the user's default language
+localize.setLocale(defaultLang);
+
+// ## The *mergeObjs* function
+// is a helper function that clones the value of various object into a new one.
+// This simplistic one is fast, but assumes no recursive objects to merge.
+function mergeObjs() {
+	var outObj = {};
+	for(var i in arguments) {
+		if(arguments[i] instanceof Object) {
+			for(var j in arguments[i]) {
+				// Does not check for collisions, newer object
+				// definitions clobber old definitions
+				outObj[j] = arguments[i][j];
+			}
+		}
+	}
+	return outObj;
+}
+
+// ## The *processDir* function
+// generates a ``translations.json`` file for the current directory, but does
+// not override the previous file -- only augments it
+function processDir(dir) {
+	// JSON object for the current directory
+	var dirJSON = {};
+	// Path where translations will go
+	var translations = path.join(dir, "translations.json");
+	// Check for pre-existing ``translations.json`` file
+	if(path.existsSync(translations)) {
+		var currJSON = JSON.parse(fs.readFileSync(translations, "utf8"));
+		dirJSON = mergeObjs(dirJSON, currJSON);
+	}
+	
+	// Build pattern matching for searchable files
+	var extRegExpStr = "(";
+	for(var i = 0; i < extensions.length; i++) {
+		extRegExpStr += extensions[i];
+		if(i < extensions.length-1) { extRegExpStr += "|"; }
+		else { extRegExpStr += ")$"; }
+	}
+	var extRegExp = new RegExp(extRegExpStr);
+
+	// Process files in the current directory
+	var files = fs.readdirSync(dir);
+	files.forEach(function(file) {
+		if(extRegExp.test(file)) {
+			processFile(path.join(dir, file), dirJSON);
+		}
+		if(recurse && fs.statSync(path.join(dir, file)).isDirectory()) {
+			processDir(path.join(dir, file));
+		}
+	});
+
+	// Output dirJSON to file
+	fs.writeFileSync(translations, JSON.stringify(dirJSON, null, "	"), "utf8");
+}
+
+// ## The *processFile* function
+// extracts all translatable pieces of a source file into the dirJSON object,
+// unless already there.
+function processFile(filename, dirJSON) {
+	// Hacky, hacky RegExp parsing right now; replace with something better
+	var fileContents = fs.readFileSync(filename, "utf8");
+	var translatables = fileContents.match(/translate\s*\([^\),]*/);
+	if(translatables) {
+		for(var i = 0; i < translatables.length; i++) {
+			if(/^translate\s*\(\s*['"](.*)['"]$/.test(translatables[i])) { // A string-looking thing
+				if(!dirJSON[RegExp.$1]) { // Does not yet exist
+					dirJSON[RegExp.$1] = {};
+				}
+				outLangs.forEach(function(lang) {
+					if(!dirJSON[RegExp.$1][lang]) { // No translation, yet
+						dirJSON[RegExp.$1][lang] = translate("MISSING TRANSLATION");
+					}
+				});
+			} else {
+				var translateMessage = translate("FOUND VARIABLE INPUT: $[1]", translatables[i]);
+				dirJSON[translateMessage] = {};
+				outLangs.forEach(function(lang) {
+					dirJSON[translateMessage][lang] = translate("MISSING TRANSLATION");
+				});
+			}
+		}
+	}
+}
+
+// Get the ball rollin'
+processDir(process.cwd());

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/localize/lib/localize.js
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/localize/lib/localize.js b/blackberry10/node_modules/localize/lib/localize.js
new file mode 100644
index 0000000..648325e
--- /dev/null
+++ b/blackberry10/node_modules/localize/lib/localize.js
@@ -0,0 +1,405 @@
+// # Localize
+// is a GNU gettext-inspired (but not conformant) localization library for
+// Node.js
+
+// Libraries, if in a CommonJS environment
+if(typeof(require) != 'undefined') {
+	var path = require('path');
+	var fs = require('fs');
+}
+
+function Localize(translations, dateFormats, defaultLocale) {
+
+	// Make sure the defaultLocale is something sane, and set the locale to
+	// its value. Also configure ``Localize`` to throw an error if missing
+	// a translation.
+	defaultLocale = typeof(defaultLocale) == "string" ? defaultLocale : "en";
+	var locale = defaultLocale;
+	var missingTranslationThrow = true;
+	
+	// ## The *mergeObjs* function
+	// is a simple helper function to create a new object based on input objects.
+	function mergeObjs() {
+		var outObj = {};
+		for(var i in arguments) {
+			if(arguments[i] instanceof Object) {
+				for(var j in arguments[i]) {
+					// Does not check for collisions, newer object
+					// definitions clobber old definitions
+					outObj[j] = arguments[i][j];
+				}
+			}
+		}
+		return outObj;
+	}
+	
+	// ## The *setLocale* function
+	// simply sets the locale to whatever is specified at the moment, as long as it
+	// is a string.
+	this.setLocale = function(newLocale) {
+		if(typeof(newLocale) == "string") {
+			locale = newLocale;
+		} else {
+			throw new Error("Locale must be a string");
+		}
+	};
+
+	// ## The *strings* object
+	// contains a series of key-val pairs to be used for translating very large strings
+	// that aren't desirable to have duplicated in several locations
+	this.strings = {};
+	
+	// ## The *getTranslations* function
+	// is a recursive function that checks the specified directory, and all child
+	// directories, for ``translations.json`` files, combines them into one JSON
+	// object, and returns them.
+	function getTranslations(currDir, translations, strings) {
+		if(path.existsSync(currDir)) {
+			// Load translations.json file in current directory, if any
+			if(path.existsSync(path.join(currDir, "translations.json"))) {
+				translations = mergeObjs(translations,
+					JSON.parse(fs.readFileSync(path.join(path.resolve(currDir), "translations.json")))
+				);
+			}
+			// Load large text translations in translations subdirectory, if it exists
+			var translationPath = path.join(currDir, "translations");
+			if(path.existsSync(translationPath) && fs.statSync(translationPath).isDirectory()) {
+				// Get all children in the translations directory
+				var pathChildren = fs.readdirSync(translationPath);
+				// Filter out all non-default translations (the ones without a lang type)
+				pathChildren.filter(function(child) {
+					return !/^.*\..*\..*/.test(child);
+				// And map these default translations into an object containing the variable name to use,
+				// the default text, and an array of translations for this text
+				}).map(function(child) {
+					return {
+						name: child.replace(/\..*$/, ""),
+						defaultText: fs.readFileSync(path.join(translationPath, child), 'utf8'),
+						// To make the array of translations for this default translation, filter out
+						// all files that do not start with the primary translation filename (minus extension), with a special
+						// case to filter out the primary translation, as well
+						translations: pathChildren.filter(function(secondChild) {
+							return (new RegExp("^" + child.replace(/\..*$/, ""))).test(secondChild) && child != secondChild;
+						// Then map this array of files into an object containing the language specified
+						// and the translation text for this language
+						}).map(function(secondChild) {
+							return {
+								lang: secondChild.replace(/\.[^\.]*$/, "").replace(/^[^\.]*\./, ""),
+								text: fs.readFileSync(path.join(translationPath, secondChild), 'utf8')
+							}
+						})
+					}
+				// For each of these long-form translation objects, add the default text to the strings object using the
+				// desired variable name, and create a translation object for all defined languages for this text.
+				}).forEach(function(translation) {
+					strings[translation.name] = translation.defaultText;
+					translations[translation.defaultText] = {};
+					translation.translations.forEach(function(lang) {
+						translations[translation.defaultText][lang.lang] = lang.text;
+					});
+				});
+			}
+			// Recurse down each directory and get the translations for that directory
+			var pathChildren = fs.readdirSync(currDir);
+			for(var child in pathChildren) {
+				var childPath = path.resolve(path.join(currDir, pathChildren[child]));
+				if(fs.statSync(childPath).isDirectory()) {
+					var tempArray = getTranslations(childPath, translations, strings);
+					translations = tempArray[0], strings = tempArray[1];
+				}
+			}
+		} else {
+			throw new Error("Translation Path Invalid");
+		}
+		return [translations, strings];
+	}
+	
+	// ## The *validateTranslations* function
+	// determines whether or not the provided JSON object is in a valid
+	// format for ``localize``.
+	function validateTranslations(newTranslations) {
+		if(typeof(newTranslations) != "object") { return false; }
+		for(var translation in newTranslations) {
+			if(typeof(translation) != "string") { return false; }
+			if(typeof(newTranslations[translation]) != "object" ) { return false; }
+			for(var lang in newTranslations[translation]) {
+				if(typeof(lang) != "string") { return false; }
+				if(typeof(newTranslations[translation][lang]) != "string") { return false; }
+			}
+		}
+		return true;
+	}
+	
+	// ## The *loadTranslations* function
+	// takes a string or object, and attempts to append the specified translation
+	// to its store of translations, either by loading all translations from the
+	// specified directory (string), or appending the object directly.
+	this.loadTranslations = function(newTranslations) {
+		if(typeof(newTranslations) == "string") {
+			var tempArray = getTranslations(newTranslations, {}, this.strings);
+			newTranslations = tempArray[0];
+			this.strings = tempArray[1];
+		}
+		if(validateTranslations(newTranslations)) {
+			translations = mergeObjs(translations, newTranslations);
+		} else {
+			throw new Error("Must provide a valid set of translations.");
+		}
+	};
+	
+	// Now that we have the infrastructure in place, let's verify that the
+	// provided translations are valid.
+	this.loadTranslations(translations);
+	
+	// ## The *clearTranslations* function
+	// simply resets the translations variable to a clean slate.
+	this.clearTranslations = function() {
+		translations = {};
+	};
+
+	// ## The *getTranslations* function
+	// simply returns the entire translations object, or returns that portion
+	// of translations matched by the elements of a provided array of text to
+	// translate
+	this.getTranslations = function(textArr) {
+		if(textArr instanceof Array) {
+			var outObj = {};
+			textArr.forEach(function(text) {
+				outObj[text] = translations[text];
+			});
+			return outObj;
+		} else {
+			return translations;
+		}
+	};
+
+	// ## The *throwOnMissingTranslation* function
+	// lets the user decide if a missing translation should cause an Error
+	// to be thrown. Turning it off for development and on for testing is
+	// recommended. The function coerces whatever it receives into a bool.
+	this.throwOnMissingTranslation = function(shouldThrow) {
+		missingTranslationThrow = !!shouldThrow;
+	};
+	
+	// ## The *buildString* function
+	// is a string-building function inspired by both ``sprintf`` and
+	// [jQuery Templates](http://api.jquery.com/category/plugins/templates/)
+	// and a small helping of RegExp. The first argument to buildString is
+	// the source string, which has special ``$[x]`` blocks, where ``x`` is
+	// a number from 1 to Infinity, matching the nth argument provided.
+	// Because of ``.toString()``, string formatting _a la_ ``sprintf`` is
+	// avoided, and the numeric identification allows the same parameter to
+	// be used multiple times, and the parameter order need not match the
+	// string referencing order (important for translations)
+	function buildString() {
+		var outString = arguments[0];
+		for(var i = 1; i < arguments.length; i++) {
+			outString = outString.replace(new RegExp("\\$\\[" + i + "\\]", "g"), arguments[i]);
+		}
+		return outString;
+	}
+	
+	// ## The *translate* function
+	// is a thin automatic substitution wrapper around ``buildString``. In
+	// fact, it short-circuits to ``buildString`` when ``locale`` equals
+	// ``defaultLocale``. Otherwise, it looks up the required translated
+	// string and executes ``buildString`` on that, instead
+	this.translate = function() {
+		if(locale == defaultLocale) {
+			return buildString.apply(this, arguments);
+		}
+		var newText = translations[arguments[0]] && translations[arguments[0]][locale] ?
+			translations[arguments[0]][locale] : null;
+		if(missingTranslationThrow && typeof(newText) != "string") {
+			throw new Error("Could not find translation for '" +
+				arguments[0] + "' in the " + locale + " locale");
+		} else if(typeof(newText) != "string") {
+			newText = arguments[0];
+		}
+		var newArr = Array.prototype.splice.call(arguments, 1, arguments.length - 1);
+		newArr.unshift(newText);
+		return buildString.apply(this, newArr);
+	};
+
+	// ## The *validateDateFormats* function
+	// determines whether or not the provided dateFormat object conforms to
+	// the necessary structure
+	function validateDateFormats(dateFormats) {
+		if(typeof(dateFormats) != "object") { return false; }
+		for(var lang in dateFormats) {
+			if(typeof(lang) != "string") { return false; }
+			if(typeof(dateFormats[lang]) != "object") { return false; }
+			if(!(dateFormats[lang].dayNames instanceof Array)) { return false; }
+			if(!(dateFormats[lang].monthNames instanceof Array)) { return false; }
+			if(typeof(dateFormats[lang].masks) != "object") { return false; }
+			if(typeof(dateFormats[lang].masks["default"]) != "string") { return false; }
+			if(dateFormats[lang].dayNames.length != 14) { return false; }
+			if(dateFormats[lang].monthNames.length != 24) { return false; }
+			for(var i = 0; i < 24; i++) {
+				if(i < 14 && typeof(dateFormats[lang].dayNames[i]) != "string") { return false; }
+				if(typeof(dateFormats[lang].monthNames[i]) != "string") { return false; }
+			}
+		}
+		return true;
+	}
+	
+	// ## The *loadDateFormats* function
+	// appends the provided ``dateFormats`` object, if valid, to the current
+	// ``dateFormats`` object. Otherwise, it throws an error.
+	this.loadDateFormats = function(newDateFormats) {
+		if(validateDateFormats(newDateFormats)) {
+			dateFormats = mergeObjs(dateFormats, newDateFormats);
+		} else {
+			throw new Error("Invalid Date Format provided");
+		}
+	};
+
+	// ## The *clearDateFormats* function
+	// resets the ``dateFormats`` object to English dates.
+	this.clearDateFormats = function() {
+		dateFormats = {
+			"en": {
+				dayNames: [
+					"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
+					"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+				],
+				monthNames: [
+					"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+					"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
+				],
+				masks: {
+					"default":      "ddd mmm dd yyyy HH:MM:ss",
+					shortDate:      "m/d/yy",
+					mediumDate:     "mmm d, yyyy",
+					longDate:       "mmmm d, yyyy",
+					fullDate:       "dddd, mmmm d, yyyy",
+					shortTime:      "h:MM TT",
+					mediumTime:     "h:MM:ss TT",
+					longTime:       "h:MM:ss TT Z",
+					isoDate:        "yyyy-mm-dd",
+					isoTime:        "HH:MM:ss",
+					isoDateTime:    "yyyy-mm-dd'T'HH:MM:ss",
+					isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"
+				}
+			}
+		};
+	};
+
+	// ## The *getDateFormats* function
+	// returns the currently-defined ``dateFormats`` object
+	this.getDateFormats = function() {
+		return dateFormats;
+	};
+	
+	// Now that we have the infrastructure in place, let's validate the
+	// optional ``dateFormats`` object if provided, or initialize it.
+	if(validateDateFormats(dateFormats)) {
+		this.loadDateFormats(dateFormats);
+	} else {
+		this.clearDateFormats();
+	}
+	
+	// The *localDate* function
+	// provides easy-to-use date localization support. Based heavily on
+	// [node-dateFormat](https://github.com/felixge/node-dateformat) by
+	// Steven Levithan <stevenlevithan.com>
+	// Scott Trenda <scott.trenda.net>
+	// Kris Kowal <cixar.com/~kris.kowal/>
+	// Felix Geisendörfer <debuggable.com>
+	// MIT Licensed, as with this library. The resultant API is one where
+	// a date string or object is the first argument, a mask string (being
+	// either a key in the ``masks`` object or an arbitrary mask is the
+	// second argument, and a third is a bool flag on whether local or UTC
+	// time should be used.
+	this.localDate = function() {
+		var	token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,
+			timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,
+			timezoneClip = /[^-+\dA-Z]/g,
+			pad = function (val, len) {
+				val = String(val);
+				len = len || 2;
+				while (val.length < len) val = "0" + val;
+				return val;
+			};
+		
+		// Regexes and supporting functions are cached through closure
+		return function (date, mask, utc) {
+			// You can't provide utc if you skip other args (use the "UTC:" mask prefix)
+			if (arguments.length == 1 &&
+				Object.prototype.toString.call(date) == "[object String]" &&
+				!/\d/.test(date)) {
+				mask = date;
+				date = undefined;
+			}
+			
+			date = date || new Date;
+			
+			if(!(date instanceof Date)) {
+				date = new Date(date);
+			}
+			
+			if(isNaN(date)) {
+				throw TypeError("Invalid date");
+			}
+			
+			mask = String(dateFormats[locale].masks[mask] || mask || dateFormats[locale].masks["default"]);
+			
+			// Allow setting the utc argument via the mask
+			if (mask.slice(0, 4) == "UTC:") {
+				mask = mask.slice(4);
+				utc = true;
+			}
+			
+			var	_ = utc ? "getUTC" : "get",
+				d = date[_ + "Date"](),
+				D = date[_ + "Day"](),
+				m = date[_ + "Month"](),
+				y = date[_ + "FullYear"](),
+				H = date[_ + "Hours"](),
+				M = date[_ + "Minutes"](),
+				s = date[_ + "Seconds"](),
+				L = date[_ + "Milliseconds"](),
+				o = utc ? 0 : date.getTimezoneOffset(),
+				flags = {
+					d:    d,
+					dd:   pad(d),
+					ddd:  dateFormats[locale].dayNames[D],
+					dddd: dateFormats[locale].dayNames[D + 7],
+					m:    m + 1,
+					mm:   pad(m + 1),
+					mmm:  dateFormats[locale].monthNames[m],
+					mmmm: dateFormats[locale].monthNames[m + 12],
+					yy:   String(y).slice(2),
+					yyyy: y,
+					h:    H % 12 || 12,
+					hh:   pad(H % 12 || 12),
+					H:    H,
+					HH:   pad(H),
+					M:    M,
+					MM:   pad(M),
+					s:    s,
+					ss:   pad(s),
+					l:    pad(L, 3),
+					L:    pad(L > 99 ? Math.round(L / 10) : L),
+					t:    H < 12 ? "a"  : "p",
+					tt:   H < 12 ? "am" : "pm",
+					T:    H < 12 ? "A"  : "P",
+					TT:   H < 12 ? "AM" : "PM",
+					Z:    utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),
+					o:    (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),
+					S:    ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]
+				};
+			
+			return mask.replace(token, function ($0) {
+				return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
+			});
+		};
+	}();
+	
+	return this;
+}
+
+// Publish as a module, if in a CommonJS environment
+if(typeof(module) != 'undefined') {
+	module.exports = Localize;
+}

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/localize/package.json
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/localize/package.json b/blackberry10/node_modules/localize/package.json
new file mode 100644
index 0000000..d709584
--- /dev/null
+++ b/blackberry10/node_modules/localize/package.json
@@ -0,0 +1,38 @@
+{
+  "name": "localize",
+  "description": "A GNU gettext-inspired (but not conformant) localization library for Node.js",
+  "homepage": "https://github.com/AGROSICA/node-localize",
+  "author": {
+    "name": "David Ellis"
+  },
+  "contributors": [
+    {
+      "name": "Steven Levithan"
+    },
+    {
+      "name": "Felix Geisendörfer"
+    },
+    {
+      "name": "Clint Andrew Hall"
+    },
+    {
+      "name": "Jerry Jalava"
+    }
+  ],
+  "version": "0.4.2",
+  "main": "./lib/localize",
+  "dependencies": {},
+  "devDependencies": {
+    "expresso": ">=0.8.1"
+  },
+  "engines": {
+    "node": "*"
+  },
+  "bin": {
+    "xlocalize": "./bin/xlocalize.js"
+  },
+  "readme": "# The *node-localize* library\nprovides a [GNU gettext](http://www.gnu.org/s/gettext/)-inspired (but not conformant) translation utility for [Node.js](http://nodejs.org) that tries to avoid some of the limitations of the ``sprintf``-bound ``gettext`` (such as translation string parameters being in a fixed order in all translation results) and \"fit in\" better than a straight port.\n\n## Installation\n\nIf you have [npm](http://npmjs.org), just type:\n\n```sh\nnpm install localize\n```\n\n## Usage\n\n``node-localize`` returns an object constructor so multiple simultaneous localization objects may be in use at once (though most cases will probably be a singleton instantiation). The only required parameter on initialization is a ``translations`` object, using the following structure:\n\n```js\nvar Localize = require('localize');\n\nvar myLocalize = new Localize({\n    \"Testing...\": {\n        \"es\": \"Pruebas...\",\n        \"sr\": \"тестирање...\"\n    },\n  
   \"Substitution: $[1]\": {\n        \"es\": \"Sustitución: $[1]\",\n        \"sr\": \"замена: $[1]\"\n    }\n});\n\nconsole.log(myLocalize.translate(\"Testing...\")); // Testing...\nconsole.log(myLocalize.translate(\"Substitution: $[1]\", 5)); // Substitution: 5\n\nmyLocalize.setLocale(\"es\");\nconsole.log(myLocalize.translate(\"Testing...\")); // Pruebas...\n\nmyLocalize.setLocale(\"sr\");\nconsole.log(myLocalize.translate(\"Substitution: $[1]\", 5)); // замена: 5\n```\n\n``node-localize`` objects can also be passed a string indicating the directory a ``translations.json`` file can be found. This directory is searched recursively for all ``translations.json`` files in all subdirectories, and their contents combined together, so you can organize your translations as you wish.\n\nThe directory is also searched recursively for directories named ``translations``. These directories are checked for special text files of the form ``varname.txt``, ``varname.es.txt``, ``varna
 me.sr.txt``, etc. The text in ``varname.txt`` is treated as the default language of the application and the ``varname.xx.txt`` are treated as translations of the text. A special ``strings`` object is created where the ``varname`` becomes a property of that object and the default language text is the value of the property. So you can also do the following:\n\n```js\nvar Localize = require('localize');\n\nvar myLocalize = new Localize('./path/to/text/files/');\n\nconsole.log(myLocalize.translate(myLocalize.strings.reallyLongText); // The contents of ./path/to/text/files/translations/reallyLongText.txt, if it exists\n\nmyLocalize.setLocale(\"es\");\nconsole.log(myLocalize.translate(myLocalize.strings.reallyLongText); // The contents of ./path/to/text/files/translations/reallyLongText.es.txt, if it exists\n```\n\n## Dates\n\nBecause date formats differ so wildly in different languages and these differences cannot be solved via simple substitution, there is also a ``localDate`` method fo
 r translating these values.\n\n```js\nvar theDate = new Date(\"4-Jul-1776\");\nvar dateLocalize = new Localize(\"./translations\");\ndateLocalize.loadDateFormats({\n\t\"es\": {\n\t\tdayNames: [\n\t\t\t'Dom', 'Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb',\n\t\t\t'Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'\n\t\t],\n\t\tmonthNames: [\n\t\t\t'Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic',\n\t\t\t'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'\n\t\t],\n\t\tmasks: {\n\t\t\t\"default\": \"dddd, d 'de' mmmm yyyy\"\n\t\t}\n\t}\n});\n\nconsole.log(dateLocalize.localDate(theDate)); // Thu Jul 04 1776 00:00:00\nconsole.log(dateLocalize.localDate(theDate, \"fullDate\")); // Thursday, July 4, 1776\nconsole.log(dateLocalize.localDate(theDate, \"mm/dd/yyyy\")); // 07/04/1776\n\ndateLocalize.setLocale(\"es\");\nconsole.log(dateLocalize.localDate(theDate)); // Ju
 eves, 4 de Julio 1776\n```\n\nThe date formatting rules and configuration have been taken from [node-dateformat](https://github.com/felixge/node-dateformat), which has been extended to support multiple simultaneous locales and subsumed into ``node-localize``.\n\n## Complete API\n\n```js\nvar myLocalize = new Localize(translationsObjOrStr, dateFormatObj, defaultLocaleStr);\n// translationsObjOrStr: a conformant translations object or a string indicating\n//     the directory where one or more conformant translations.json files are stored\n// dateFormatObj: a conformant date format object, containing one or more locales\n//     if not specified, will auto-generate an 'en' locale; if initially specified,\n//     will *overwrite* this auto-generated locale object\n// defaultLocale: the locale of all keys in the translations object. Defaults to 'en'\n```\n\n```js\nmyLocalize.setLocale(localeStr);\n// localeStr: a locale string to switch to\n```\n\n```js\nmyLocalize.loadTranslations(trans
 lationsObjOrStr);\n// translationsObjOrStr: a conformant translations object or a string indicating\n//     the directory where one or more conformant translations.json files are stored\n//     Multiple calls to loadTranslations *appends* the keys to the translations\n//     object in memory (overwriting duplicate keys).\n```\n\n```js\nmyLocalize.clearTranslations();\n// Wipes out the translations object entirely (if a clean reload is desired)\n```\n\n```js\nmyLocalize.throwOnMissingTranslation(throwBool);\n// throwBool: Boolean indicating whether or not missing translations should\n//     throw an error or be silently ignored and the text stay in the default\n//     locale. Useful for development to turn off.\n```\n\n```js\nmyLocalize.translate(translateStr, arg1, arg2, ...);\n// translateStr: The string to be translated and optionally perform a\n//     substitution of specified args into. Arguments are specified in a RegExp\n//     style by number starting with 1 (it is the first 
 argument that can be\n//     used and also is the arguments[1] value...), while using a jQuery-style\n//     demarcation of $[x], where x is the argument number.\n```\n\n```js\nmyLocalize.loadDateFormats(dateFormatObj);\n// dateFormatObj: a conformant date format object, containing one or more locales\n//     Specified locales are appended to the internal object just like\n//     loadTranslations.\n```\n\n```js\nmyLocalize.clearDateFormats();\n// Resets the date formats object to just the 'en' locale.\n```\n\n```js\nmyLocalize.localDate(dateObjOrStr, maskStr, utcBool)\n// dateObjOrStr: the date object or string to format as desired in the current\n//     locale.\n// maskStr: the predefined mask to use, or a custom mask.\n// utcBool: a boolean indicating whether the timezone should be local or UTC\n```\n\n```js\nmyLocalize.strings\n// Object of key-value pairs defined by files in ``translations`` directories\n// Key is the filename (sans extension) and value is the default language\n
 // text. Useful for translating very large blocks of text that shouldn't really\n// exist in code.\n```\n\n## _xlocalize_ CLI Utility\n\nStarting at version 0.2.0, ``node-localize``, when installed via NPM, adds an ``xlocalize`` utility command to the _PATH_, which allows for automatic construction of ``translations.json`` files (and can be re-run in the future to update existing files without clobbering any current translations present). It's command switches are as follows:\n\n```\nxlocalize USAGE:\n\n-l\tSet the default language for the translations.json file(s) (default: en)\n-r\tSet xlocalize to generate translations.json files recursively (default)\n-R\tSet xlocalize to only generate a translations.json file for the current directory\n-e\tSet the file extensions to include for translation (default: html,js)\n-t\tSet the languages to translate to (comma separated)\n-h\tShow this help message.\n```\n\nFor example, to create a ``translations.json`` file in the current directory o
 nly that will translate from English to Spanish, Portuguese, Italian, and French for HTML and JS files:\n\n```sh\nxlocalize -R -t es,pt,it,fr\n```\n\nAnd if a new language, such as Serbian, is to be translated at a later time, you can use the command:\n```sh\nxlocalize -R -t es,pt,it,fr,sr\n```\n\n## [Express](http://expressjs.com) Integration Tips\n\nIf your website supports multiple languages (probably why you're using this library!), you'll want to translate the page content for each supported language. The following snippets of code should make it easy to use within Express.\n\n### Middleware to switch locale on request\n\n```js\napp.configure(function() {\n    ...\n    app.use(function(request, response, next) {\n        var lang = request.session.lang || \"en\";\n        localize.setLocale(lang);\n        next();\n    });\n    ...\n});\n```\n\nI'm assuming you're storing their language preference inside of a session, but the logic can be easily tweaked for however you detect w
 hich language to show.\n\n### Export *translate*, *localDate*, and *strings* as static helpers\n\n```js\napp.helpers({\n    ...\n    translate: localize.translate,\n    localDate: localize.localDate,\n    strings: localize.strings\n});\n```\n\nYour controllers shouldn't really even be aware of any localization issues; the views should be doing that, so this ought to be enough configuration within your ``app.js`` file.\n\n### Using *translate*, *localDate*, and *strings* in your views\n\n```html\n<h1>${translate(\"My Awesome Webpage\")}</h1>\n\n<h2>${translate(\"By: $[1]\", webpageAuthor)}</h2>\n\n<h3>${translate(\"Published: $[1]\", localDate(publicationDate))}</h3>\n\n{{if translate(strings.reallyLongPost) == strings.reallyLongPost}}\n<strong>${translate(\"Warning: The following content is in English.\")}</strong>\n{{/if}}\n\n{{html translate(strings.reallyLongPost)}}\n```\n\nI'm using [jQuery Templates for Express](https://github.com/kof/node-jqtpl) here, but it should be easy to 
 translate to whatever templating language you prefer.\n\n## Planned Features\n\n* Browser compatibility (use same functions for client-side jQuery Templates, for instance)\n* Optional Country Code support (that falls back to baseline language translation if a specific country code is missing) for regional language differences\n* Numeric localization (1,234,567.89 versus 1.234.567,89 versus 1 234 567,89 versus [Japanese Numerals](http://en.wikipedia.org/wiki/Japanese_numerals) [no idea how to handle that one at the moment])\n* Currency localization; not just representing $100.00 versus 100,00$, but perhaps hooking into currency conversion, as well.\n* Pluralization; one area gettext still beats node-localize is the ability to pluralize words correctly when given the number to pluralize against.\n\n## License (MIT)\n\nCopyright (C) 2011 by Agrosica, Inc, David Ellis, Felix Geisendörfer, Steven Levithan, Scott Trenda, Kris Kowal, Jerry Jalava, Clint Andrew Hall.\n\nPermission is hereb
 y granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 DEALINGS IN\nTHE SOFTWARE.\n",
+  "readmeFilename": "README.md",
+  "_id": "localize@0.4.2",
+  "_from": "localize@*0.4.2"
+}

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/localize/test/localize.test.js
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/localize/test/localize.test.js b/blackberry10/node_modules/localize/test/localize.test.js
new file mode 100644
index 0000000..49dd92b
--- /dev/null
+++ b/blackberry10/node_modules/localize/test/localize.test.js
@@ -0,0 +1,179 @@
+var assert = require('assert');
+var Localize = require('../lib/localize');
+
+module.exports = {
+	'test empty initialization error': function() {
+		assert.throws(function() {
+			var badLocalize = new Localize();
+		}, function(err) {
+			if(err instanceof Error &&
+				err.message == "Must provide a valid set of translations.") {
+				return true;
+			}
+			return false;
+		});
+	},
+	'test bad translations var error': function() {
+		assert.throws(function() {
+			var badLocalize = new Localize([1,2,3]);
+		}, function(err) {
+			if(err instanceof Error &&
+				err.message == "Must provide a valid set of translations.") {
+				return true;
+			}
+			return false;
+		});
+	},
+	'test bad translations path error': function() {
+		assert.throws(function() {
+			var badLocalize = new Localize("/nowheresville");
+		}, function(err) {
+			if(err instanceof Error &&
+				err.message == "Translation Path Invalid") {
+				return true;
+			}
+			return false;
+		});
+	},
+	'test good translations var': function() {
+		assert.doesNotThrow(function() {
+			var goodLocalize = new Localize({
+				"Testing...": {
+					"es": "Pruebas..."
+				}
+			});
+		});
+	},
+	'test good translations path': function() {
+		assert.doesNotThrow(function() {
+			var goodLocalize = new Localize("./translations");
+		});
+	},
+	'test bad setLocale var': function() {
+		assert.throws(function() {
+			var goodLocalize = new Localize("./translations");
+			goodLocalize.setLocale(23);
+		}, function(err) {
+			if(err instanceof Error &&
+				err.message == "Locale must be a string") {
+				return true;
+			}
+			return false;
+		});
+	},
+	'test good setLocale var': function() {
+		assert.doesNotThrow(function() {
+			var goodLocalize = new Localize("./translations");
+			goodLocalize.setLocale("es");
+		});
+	},
+	'test bad translate string': function() {
+		assert.throws(function() {
+			var goodLocalize = new Localize("./translations");
+			goodLocalize.setLocale("es");
+			goodLocalize.translate("Test2");
+		}, function(err) {
+			if(err instanceof Error &&
+				err.message == "Could not find translation for 'Test2' in the es locale") {
+				return true;
+			}
+			return false;
+		});
+	},
+	'test good translate string': function() {
+		assert.doesNotThrow(function() {
+			var goodLocalize = new Localize("./translations");
+			goodLocalize.setLocale("es");
+			assert.strictEqual(goodLocalize.translate("Testing..."), "Pruebas...");
+		});
+	},
+	'test good translate nop': function() {
+		var goodLocalize = new Localize("./translations");
+		assert.strictEqual(goodLocalize.translate("Testing..."), "Testing...");
+	},
+	'test good translate substitution': function() {
+		var goodLocalize = new Localize("./translations");
+		assert.strictEqual(goodLocalize.translate("Substitution: $[1]", 5), "Substitution: 5");
+		goodLocalize.setLocale("es");
+		assert.strictEqual(goodLocalize.translate("Substitution: $[1]", 5), "Sustitución: 5");
+	},
+	'test good translate multiple substitution': function() {
+		var goodLocalize = new Localize("./translations");
+		assert.strictEqual(goodLocalize.translate("Multiple substitution: $[1], $[2]", 5, 25), "Multiple substitution: 5, 25");
+		goodLocalize.setLocale("es");
+		assert.strictEqual(goodLocalize.translate("Multiple substitution: $[1], $[2]", 5, 25), "Sustitución múltiple: 5, 25");
+	},
+	'test bad dateFormat var initialization': function() {
+		assert.doesNotThrow(function() {
+			var goodLocalize = new Localize("./translations", 25);
+		});
+	},
+	'test bad dateFormat var post-initialization': function() {
+		assert.throws(function() {
+			var badLocalize = new Localize("./translations", 25);
+			badLocalize.loadDateFormats(25);
+		}, function(err) {
+			if(err instanceof Error &&
+				err.message == "Invalid Date Format provided") {
+				return true;
+			}
+			return false;
+		});
+	},
+	'test good dateFormat var post-initialization': function() {
+		assert.doesNotThrow(function() {
+			var goodLocalize = new Localize("./translations");
+			goodLocalize.loadDateFormats({
+				"es": {
+					dayNames: [
+						'Dom', 'Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb',
+						'Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'
+					],
+					monthNames: [
+						'Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic',
+						'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'
+					],
+					masks: {
+						"default": "dddd, d 'de' mmmm yyyy"
+					}
+				}
+			});
+		});
+	},
+	'test good localDate': function() {
+		var theDate = new Date("4-Jul-1776");
+		var goodLocalize = new Localize("./translations");
+		goodLocalize.loadDateFormats({
+			"es": {
+				dayNames: [
+					'Dom', 'Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb',
+					'Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'
+				],
+				monthNames: [
+					'Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic',
+					'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'
+				],
+				masks: {
+					"default": "dddd, d 'de' mmmm yyyy"
+				}
+			}
+		});
+		assert.strictEqual(goodLocalize.localDate(theDate), "Thu Jul 04 1776 00:00:00");
+		assert.strictEqual(goodLocalize.localDate(theDate, "fullDate"), "Thursday, July 4, 1776");
+		assert.strictEqual(goodLocalize.localDate(theDate, "mm/dd/yyyy"), "07/04/1776");
+		goodLocalize.setLocale("es");
+		assert.strictEqual(goodLocalize.localDate(theDate), "Jueves, 4 de Julio 1776");
+	},
+	'test good missing translation ignore': function() {
+		var goodLocalize = new Localize("./translations");
+		goodLocalize.throwOnMissingTranslation(false);
+		goodLocalize.setLocale("es");
+		assert.strictEqual(goodLocalize.translate("Not found"), "Not found");
+	},
+	'test translations dir': function() {
+		var goodLocalize = new Localize('./translations');
+		assert.strictEqual(goodLocalize.translate(goodLocalize.strings.helloWorld), "Hello, World!\n");
+		goodLocalize.setLocale("es");
+		assert.strictEqual(goodLocalize.translate(goodLocalize.strings.helloWorld), "¡Hola, mundo!\n");
+	}
+};

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/localize/test/translations/subsitution/translations.json
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/localize/test/translations/subsitution/translations.json b/blackberry10/node_modules/localize/test/translations/subsitution/translations.json
new file mode 100644
index 0000000..1a68bb3
--- /dev/null
+++ b/blackberry10/node_modules/localize/test/translations/subsitution/translations.json
@@ -0,0 +1,8 @@
+{
+	"Substitution: $[1]": {
+		"es": "Sustitución: $[1]"
+	},
+	"Multiple substitution: $[1], $[2]": {
+		"es": "Sustitución múltiple: $[1], $[2]"
+	}
+}

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/localize/test/translations/translations.json
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/localize/test/translations/translations.json b/blackberry10/node_modules/localize/test/translations/translations.json
new file mode 100644
index 0000000..e83ace0
--- /dev/null
+++ b/blackberry10/node_modules/localize/test/translations/translations.json
@@ -0,0 +1,5 @@
+{
+	"Testing...": {
+		"es": "Pruebas..."
+	}
+}

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/localize/test/translations/translations/helloWorld.es.txt
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/localize/test/translations/translations/helloWorld.es.txt b/blackberry10/node_modules/localize/test/translations/translations/helloWorld.es.txt
new file mode 100644
index 0000000..59b3e13
--- /dev/null
+++ b/blackberry10/node_modules/localize/test/translations/translations/helloWorld.es.txt
@@ -0,0 +1 @@
+¡Hola, mundo!

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/localize/test/translations/translations/helloWorld.txt
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/localize/test/translations/translations/helloWorld.txt b/blackberry10/node_modules/localize/test/translations/translations/helloWorld.txt
new file mode 100644
index 0000000..8ab686e
--- /dev/null
+++ b/blackberry10/node_modules/localize/test/translations/translations/helloWorld.txt
@@ -0,0 +1 @@
+Hello, World!

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/localize/test/xlocalize.test.sh
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/localize/test/xlocalize.test.sh b/blackberry10/node_modules/localize/test/xlocalize.test.sh
new file mode 100755
index 0000000..700cb5b
--- /dev/null
+++ b/blackberry10/node_modules/localize/test/xlocalize.test.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+testdir=`pwd`
+cd xlocalize
+../../bin/xlocalize.js -t es,pt,it,fr
+test1=`diff translations.json ../xlocalize.testfile1.json`
+if [ "$test1" = "" ]
+then
+	cd subdir
+	test2=`diff translations.json ../../xlocalize.testfile2.json`
+	if [ "$test2" = "" ]
+	then
+		cd ..
+		../../bin/xlocalize.js -t es,pt,it,fr,sr
+		test3=`diff translations.json ../xlocalize.testfile3.json`
+		if [ "$test3" = "" ]
+		then
+			cd subdir
+			test4=`diff translations.json ../../xlocalize.testfile4.json`
+			if [ "$test4" = "" ]
+			then
+				echo "Success"
+			else
+				echo "testfile4 Failed";
+			fi
+		else
+			echo "testfile3 Failed";
+		fi
+	else
+		echo "testfile2 Failed";
+	fi
+else
+	echo "testfile1 Failed";
+fi
+cd $testdir
+rm xlocalize/translations.json
+rm xlocalize/subdir/translations.json

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/localize/test/xlocalize.testfile1.json
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/localize/test/xlocalize.testfile1.json b/blackberry10/node_modules/localize/test/xlocalize.testfile1.json
new file mode 100644
index 0000000..3ff0677
--- /dev/null
+++ b/blackberry10/node_modules/localize/test/xlocalize.testfile1.json
@@ -0,0 +1,8 @@
+{
+	"This page is in English.": {
+		"es": "MISSING TRANSLATION",
+		"pt": "MISSING TRANSLATION",
+		"it": "MISSING TRANSLATION",
+		"fr": "MISSING TRANSLATION"
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/localize/test/xlocalize.testfile2.json
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/localize/test/xlocalize.testfile2.json b/blackberry10/node_modules/localize/test/xlocalize.testfile2.json
new file mode 100644
index 0000000..8e9ccdf
--- /dev/null
+++ b/blackberry10/node_modules/localize/test/xlocalize.testfile2.json
@@ -0,0 +1,8 @@
+{
+	"You called foo!": {
+		"es": "MISSING TRANSLATION",
+		"pt": "MISSING TRANSLATION",
+		"it": "MISSING TRANSLATION",
+		"fr": "MISSING TRANSLATION"
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/localize/test/xlocalize.testfile3.json
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/localize/test/xlocalize.testfile3.json b/blackberry10/node_modules/localize/test/xlocalize.testfile3.json
new file mode 100644
index 0000000..18d86f7
--- /dev/null
+++ b/blackberry10/node_modules/localize/test/xlocalize.testfile3.json
@@ -0,0 +1,9 @@
+{
+	"This page is in English.": {
+		"es": "MISSING TRANSLATION",
+		"pt": "MISSING TRANSLATION",
+		"it": "MISSING TRANSLATION",
+		"fr": "MISSING TRANSLATION",
+		"sr": "MISSING TRANSLATION"
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/localize/test/xlocalize.testfile4.json
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/localize/test/xlocalize.testfile4.json b/blackberry10/node_modules/localize/test/xlocalize.testfile4.json
new file mode 100644
index 0000000..7ee91e9
--- /dev/null
+++ b/blackberry10/node_modules/localize/test/xlocalize.testfile4.json
@@ -0,0 +1,9 @@
+{
+	"You called foo!": {
+		"es": "MISSING TRANSLATION",
+		"pt": "MISSING TRANSLATION",
+		"it": "MISSING TRANSLATION",
+		"fr": "MISSING TRANSLATION",
+		"sr": "MISSING TRANSLATION"
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/localize/test/xlocalize/subdir/test2.js
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/localize/test/xlocalize/subdir/test2.js b/blackberry10/node_modules/localize/test/xlocalize/subdir/test2.js
new file mode 100644
index 0000000..f05ca6a
--- /dev/null
+++ b/blackberry10/node_modules/localize/test/xlocalize/subdir/test2.js
@@ -0,0 +1,3 @@
+function foo() {
+	alert(translate("You called foo!"));
+}

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/localize/test/xlocalize/test.html
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/localize/test/xlocalize/test.html b/blackberry10/node_modules/localize/test/xlocalize/test.html
new file mode 100644
index 0000000..ce37ee7
--- /dev/null
+++ b/blackberry10/node_modules/localize/test/xlocalize/test.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+
+<html>
+	<head>
+		<title>Test Doc!</title>
+	</head>
+	<body>
+		{{if session.lang != "en"}}
+			<h1>${translate("This page is in English.")}</h1>
+		{{/if}}
+		Foo. Foobar. Tada.
+	</body>
+</html>

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/net-ping/.hgignore
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/net-ping/.hgignore b/blackberry10/node_modules/net-ping/.hgignore
new file mode 100644
index 0000000..13cfce5
--- /dev/null
+++ b/blackberry10/node_modules/net-ping/.hgignore
@@ -0,0 +1,2 @@
+syntax: glob
+node_modules

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/net-ping/.hgtags
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/net-ping/.hgtags b/blackberry10/node_modules/net-ping/.hgtags
new file mode 100644
index 0000000..7730a61
--- /dev/null
+++ b/blackberry10/node_modules/net-ping/.hgtags
@@ -0,0 +1,18 @@
+9c3a64710c2fe43626ff9a63f3f5869dd1bfeb6e 1.0.0
+b1424b13eeb49c48692849c5b8616b0ba78529f7 1.0.1
+b1424b13eeb49c48692849c5b8616b0ba78529f7 1.0.1
+b0bbf8d3877664bd4ebc6b06bde6f81b8e36bfff 1.0.1
+af474759ad43eaeb6fae62be95b6194de8675ff2 1.0.2
+3af98475085396f6de474bc797f25784046a7ff4 1.1.0
+56c5153f97484cca265c26cc000e07f54a8bb01d 1.1.1
+3755c403b4ac77543ca303659017713c18e459bd 1.1.2
+b95860ddebe2366967b024d1c1818e06005eda49 1.1.3
+5f06497425fa2f31e36b22951dba5e6d08365fa9 1.1.5
+65d8b86b0b2667948a09fee2aa9997d93112575a 1.1.6
+a1b6fbaeda9d93da9a4db17be687667907b7ca86 1.1.7
+a1b6fbaeda9d93da9a4db17be687667907b7ca86 1.1.7
+80b8cf0dd0314e0828cdb3ad9a0955282306a914 1.1.7
+80b8cf0dd0314e0828cdb3ad9a0955282306a914 1.1.7
+7add610f4d27355af05f24af24505c7f86d484a6 1.1.7
+7a1911146a69d7028a27ebd8d30e1257336ba15c 1.1.8
+1b5f2a51510ca8304a95c9b352cd26cba0d8b0a7 1.1.9

http://git-wip-us.apache.org/repos/asf/cordova-blackberry/blob/1139813c/blackberry10/node_modules/net-ping/README.md
----------------------------------------------------------------------
diff --git a/blackberry10/node_modules/net-ping/README.md b/blackberry10/node_modules/net-ping/README.md
new file mode 100644
index 0000000..7f2d197
--- /dev/null
+++ b/blackberry10/node_modules/net-ping/README.md
@@ -0,0 +1,473 @@
+
+# net-ping - [homepage][homepage]
+
+This module implements ICMP Echo (ping) support for [Node.js][nodejs].
+
+This module is installed using [node package manager (npm)][npm]:
+
+    npm install net-ping
+
+It is loaded using the `require()` function:
+
+    var ping = require ("net-ping");
+
+A ping session can then be created to ping or trace route to many hosts:
+
+    var session = ping.createSession ();
+
+    session.pingHost (target, function (error, target) {
+        if (error)
+            console.log (target + ": " + error.toString ());
+        else
+            console.log (target + ": Alive");
+    });
+
+[homepage]: http://re-tool.org "Homepage"
+[nodejs]: http://nodejs.org "Node.js"
+[npm]: https://npmjs.org/ "npm"
+
+# Network Protocol Support
+
+This module supports IPv4 using the ICMP, and IPv6 using the ICMPv6.
+
+# Error Handling
+
+Each request exposed by this module requires one or more mandatory callback
+functions.  Callback functions are typically provided an `error` argument.
+
+All errors are sub-classes of the `Error` class.  For timed out errors the
+error passed to the callback function will be an instance of the
+`ping.RequestTimedOutError` class, with the exposed `message` attribute set
+to `Request timed out`.
+
+This makes it easy to determine if a host responded, a time out occurred, or
+whether an error response was received:
+
+    session.pingHost ("1.2.3.4", function (error, target) {
+        if (error)
+            if (error instanceof ping.RequestTimedOutError)
+                console.log (target + ": Not alive");
+            else
+                console.log (target + ": " + error.toString ());
+        else
+            console.log (target + ": Alive");
+    });
+
+In addition to the the `ping.RequestTimedOutError` class, the following errors
+are also exported by this module to wrap ICMP error responses:
+
+ * `DestinationUnreachableError`
+ * `PacketTooBigError`
+ * `ParameterProblemError`
+ * `RedirectReceivedError`
+ * `SourceQuenchError`
+ * `TimeExceededError`
+
+These errors are typically reported by hosts other than the intended target.
+In all cases each class exposes a `source` attribute which will specify the
+host who reported the error (which could be the intended target).  This will
+also be included in the errors `message` attribute, i.e.:
+
+    $ sudo node example/ping-ttl.js 1 192.168.2.10 192.168.2.20 192.168.2.30
+    192.168.2.10: Alive
+    192.168.2.20: TimeExceededError: Time exceeded (source=192.168.1.1)
+    192.168.2.30: Not alive
+
+The `Session` class will emit an `error` event for any other error not
+directly associated with a request.  This is typically an instance of the
+`Error` class with the errors `message` attribute specifying the reason.
+
+# Packet Size
+
+By default ICMP echo request packets sent by this module are 16 bytes in size.
+Some implementations cannot cope with such small ICMP echo requests.  For
+example, some implementations will return an ICMP echo reply, but will include
+an incorrect ICMP checksum.
+
+This module exposes a `packetSize` option to the `createSession()` method which
+specifies how big ICMP echo request packets should be:
+
+    var session = ping.createSession ({packetSize: 64});
+
+# Round Trip Times
+
+Some callbacks used by methods exposed by this module provide two instances of
+the JavaScript `Date` class specifying when the first ping was sent for a
+request, and when a request completed.
+
+These parameters are typically named `sent` and `rcvd`, and are provided to
+help round trip time calculation.
+
+A request can complete in one of two ways.  In the first, a ping response is
+received and `rcvd - sent` will yield the round trip time for the request in
+milliseconds.
+
+In the second, no ping response is received resulting in a request time out.
+In this case `rcvd - sent` will yield the total time spent waiting for each
+retry to timeout if any.  For example, if the `retries` option to the
+`createSession()` method was specified as `2` and `timeout` as `2000` then
+`rcvd - sent` will yield more than `6000` milliseconds.
+
+Although this module provides instances of the `Date` class to help round trip
+time calculation the dates and times represented in each instance should not be
+considered 100% accurate.
+
+Environmental conditions can affect when a date and time is actually
+calculated, e.g. garbage collection introducing a delay or the receipt of many
+packets at once.  There are also a number of functions through which received
+packets must pass, which can also introduce a slight variable delay.
+
+Throughout development experience has shown that, in general the smaller the
+round trip time the less accurate it will be - but the information is still
+useful nonetheless.
+
+# Constants
+
+The following sections describe constants exported and used by this module.
+
+## ping.NetworkProtocol
+
+This object contains constants which can be used for the `networkProtocol`
+option to the `createSession()` function exposed by this module.  This option
+specifies the IP protocol version to use when creating the raw socket.
+
+The following constants are defined in this object:
+
+ * `IPv4` - IPv4 protocol
+ * `IPv6` - IPv6 protocol
+
+# Using This Module
+
+The `Session` class is used to issue ping and trace route requests to many
+hosts.  This module exports the `createSession()` function which is used to
+create instances of the `Session` class.
+
+## ping.createSession ([options])
+
+The `createSession()` function instantiates and returns an instance of the
+`Session` class:
+
+    // Default options
+    var options = {
+        networkProtocol: ping.NetworkProtocol.IPv4,
+        packetSize: 16,
+        retries: 1,
+        sessionId: (process.pid % 65535),
+        timeout: 2000,
+        ttl: 128
+    };
+    
+    var session = ping.createSession (options);
+
+The optional `options` parameter is an object, and can contain the following
+items:
+
+ * `networkProtocol` - Either the constant `ping.NetworkProtocol.IPv4` or the
+   constant `ping.NetworkProtocol.IPv6`, defaults to the constant
+   `ping.NetworkProtocol.IPv4`
+ * `packetSize` - How many bytes each ICMP echo request packet should be,
+   defaults to `16`, if the value specified is less that `12` then the value
+   `12` will be used (8 bytes are required for the ICMP packet itself, then 4
+   bytes are required to encode a unique session ID in the request and response
+   packets)
+ * `retries` - Number of times to re-send a ping requests, defaults to `1`
+ * `sessionId` - A unique ID used to identify request and response packets sent
+   by this instance of the `Session` class, valid numbers are in the range of
+   `1` to `65535`, defaults to the value of `process.pid % 65535`
+ * `timeout` - Number of milliseconds to wait for a response before re-trying
+   or failing, defaults to `2000`
+ * `ttl` - Value to use for the IP header time to live field, defaults to `128`
+
+After creating the ping `Session` object an underlying raw socket will be
+created.  If the underlying raw socket cannot be opened an exception with be
+thrown.  The error will be an instance of the `Error` class.
+
+Seperate instances of the `Session` class must be created for IPv4 and IPv6.
+
+## session.on ("close", callback)
+
+The `close` event is emitted by the session when the underlying raw socket
+is closed.
+
+No arguments are passed to the callback.
+
+The following example prints a message to the console when the underlying raw
+socket is closed:
+
+    session.on ("close", function () {
+        console.log ("socket closed");
+    });
+
+## session.on ("error", callback)
+
+The `error` event is emitted by the session when the underlying raw socket
+emits an error.
+
+The following arguments will be passed to the `callback` function:
+
+ * `error` - An instance of the `Error` class, the exposed `message` attribute
+   will contain a detailed error message.
+
+The following example prints a message to the console when an error occurs
+with the underlying raw socket, the session is then closed:
+
+    session.on ("error", function (error) {
+        console.log (error.toString ());
+        session.close ();
+    });
+
+## session.close ()
+
+The `close()` method closes the underlying raw socket, and cancels all
+outstanding requsts.
+
+The calback function for each outstanding ping requests will be called.  The
+error parameter will be an instance of the `Error` class, and the `message`
+attribute set to `Socket forcibly closed`.
+
+The sessoin can be re-used simply by submitting more ping requests, a new raw
+socket will be created to serve the new ping requests.  This is a way in which
+to clear outstanding requests.
+
+The following example submits a ping request and prints the target which
+successfully responded first, and then closes the session which will clear the
+other outstanding ping requests.
+
+    var targets = ["1.1.1.1", "2.2.2.2", "3.3.3.3"];
+    
+    for (var i = 0; i < targets.length; i++) {
+        session.pingHost (targets[i], function (error, target) {
+            if (! error) {
+                console.log (target);
+                session.close (); 
+            }
+        });
+    }
+
+## session.pingHost (target, callback)
+
+The `pingHost()` method sends a ping request to a remote host.
+
+The `target` parameter is the dotted quad formatted IP address of the target
+host for IPv4 sessions, or the compressed formatted IP address of the target
+host for IPv6 sessions.
+
+The `callback` function is called once the ping requests is complete.  The
+following arguments will be passed to the `callback` function:
+
+ * `error` - Instance of the `Error` class or a sub-class, or `null` if no
+   error occurred
+ * `target` - The target parameter as specified in the request
+   still be the target host and NOT the responding gateway
+ * `sent` - An instance of the `Date` class specifying when the first ping
+   was sent for this request (refer to the Round Trip Time section for more
+   information)
+ * `rcvd` - An instance of the `Date` class specifying when the request
+   completed (refer to the Round Trip Time section for more information)
+
+The following example sends a ping request to a remote host:
+
+    var target = "fe80::a00:27ff:fe2a:3427";
+
+    session.pingHost (target, function (error, target, sent, rcvd) {
+        var ms = rcvd - sent;
+        if (error)
+            console.log (target + ": " + error.toString ());
+        else
+            console.log (target + ": Alive (ms=" + ms + ")");
+    });
+
+## session.traceRoute (target, ttl, feedCallback, doneCallback)
+
+The `traceRoute()` method provides similar functionality to the trace route
+utility typically provided with most networked operating systems.
+
+The `target` parameter is the dotted quad formatted IP address of the target
+host for IPv4 sessions, or the compressed formatted IP address of the target
+host for IPv6 sessions.  The optional `ttl` parameter specifies the maximum
+number of hops used by the trace route and defaults to the `ttl` options
+parameter as defined by the `createSession()` method.
+
+Some hosts do not respond to ping requests when the time to live is `0`, that
+is they will not send back an time exceeded error response.  Instead of
+stopping the trace route at the first time out this method will move on to the
+next hop, by increasing the time to live by 1.  It will do this 2 times,
+meaning that a trace route will continue until the target host responds or at
+most 3 request time outs are experienced.
+
+Each requst is subject to the `retries` and `timeout` option parameters to the
+`createSession()` method.  That is, requests will be retried per hop as per
+these parameters.
+
+This method will not call a single callback once the trace route is complete.
+Instead the `feedCallback` function will be called each time a ping response is
+received or a time out occurs. The following arguments will be passed to the
+`feedCallback` function:
+
+ * `error` - Instance of the `Error` class or a sub-class, or `null` if no
+   error occurred
+ * `target` - The target parameter as specified in the request
+ * `ttl` - The time to live used in the request which triggered this respinse
+ * `sent` - An instance of the `Date` class specifying when the first ping
+   was sent for this request (refer to the Round Trip Time section for more
+   information)
+ * `rcvd` - An instance of the `Date` class specifying when the request
+   completed (refer to the Round Trip Time section for more information)
+
+Once a ping response has been received from the target, or more than three
+request timed out errors are experienced, the `doneCallback` function will be
+called. The following arguments will be passed to the `doneCallback` function:
+
+ * `error` - Instance of the `Error` class or a sub-class, or `null` if no
+   error occurred
+ * `target` - The target parameter as specified in the request
+
+Once the `doneCallback` function has been called the request is complete and
+the `requestCallback` function will no longer be called.
+
+If the `feedCallback` function returns a true value when called the trace route
+will stop and the `doneCallback` will be called.
+
+The following example initiates a trace route to a remote host:
+
+    function doneCb (error, target) {
+        if (error)
+            console.log (target + ": " + error.toString ());
+        else
+            console.log (target + ": Done");
+    }
+
+    function feedCb (error, target, ttl, sent, rcvd) {
+        var ms = rcvd - sent;
+        if (error) {
+            if (error instanceof ping.TimeExceededError) {
+                console.log (target + ": " + error.source + " (ttl="
+                        + ttl + " ms=" + ms +")");
+            } else {
+                console.log (target + ": " + error.toString ()
+                        + " (ttl=" + ttl + " ms=" + ms +")");
+            }
+        } else {
+            console.log (target + ": " + target + " (ttl=" + ttl
+                    + " ms=" + ms +")");
+        }
+    }
+
+    session.traceRoute ("192.168.10.10", 10, feedCb, doneCb);
+
+# Example Programs
+
+Example programs are included under the modules `example` directory.
+
+# Bugs & Known Issues
+
+None, yet!
+
+Bug reports should be sent to <st...@gmail.com>.
+
+# Changes
+
+## Version 1.0.0 - 03/02/2013
+
+ * Initial release
+
+## Version 1.0.1 - 04/02/2013
+
+ * Minor corrections to the README.md
+ * Add note to README.md about error handling
+ * Timed out errors are now instances of the `ping.RequestTimedOutError`
+   object
+
+## Version 1.0.2 - 11/02/2013
+
+ * The RequestTimedOutError class is not being exported
+
+## Version 1.1.0 - 13/02/2013
+
+ * Support IPv6
+
+## Version 1.1.1 - 15/02/2013
+
+ * The `ping.Session.close()` method was not undefining the sessions raw
+   socket after closing
+ * Return self from the `pingHost()` method to chain method calls 
+
+## Version 1.1.2 - 04/03/2013
+
+ * Use the `raw.Socket.pauseRecv()` and `raw.Socket.resumeRecv()` methods
+   instead of closing a socket when there are no more outstanding requests
+
+## Version 1.1.3 - 07/03/2013
+
+ * Sessions were limited to sending 65535 ping requests
+
+## Version 1.1.4 - 09/04/2013
+
+ * Add the `packetSize` option to the `createSession()` method to specify how
+   many bytes each ICMP echo request packet should be
+
+## Version 1.1.5 - 17/05/2013
+
+ * Incorrectly parsing ICMP error responses resulting in responses matching
+   the wrong request
+ * Use a unique session ID per instance of the `Session` class to identify
+   requests and responses sent by a session
+ * Added the (internal) `_debugRequest()` and `_debugResponse()` methods, and
+   the `_debug` option to the `createSession()` method
+ * Added example programs `ping-ttl.js` and `ping6-ttl.js`
+ * Use MIT license instead of GPL
+
+## Version 1.1.6 - 17/05/2013
+
+ * Session IDs are now 2 bytes (previously 1 byte), and request IDs are also
+   now 2 bytes (previously 3 bytes)
+ * Each ICMP error response now has an associated error class (e.g. the
+   `Time exceeded` response maps onto the `ping.TimeExceededError` class)
+ * Call request callbacks with an error when there are no free request IDs
+   because of too many outstanding requests
+
+## Version 1.1.7 - 19/05/2013
+
+ * Added the `traceRoute()` method
+ * Added the `ttl` option parameter to the `createSession()` method, and
+   updated the example programs `ping-ttl.js` and `ping6-ttl.js` to use it
+ * Response callback for `pingHost()` now includes two instances of the
+   `Date` class to specify when a request was sent and a response received
+
+## Version 1.1.8 - 01/07/2013
+
+ * Use `raw.Socket.createChecksum()` instead of automatic checksum generation
+
+## Version 1.1.9 - 01/07/2013
+
+ * Use `raw.Socket.writeChecksum()` instead of manually rendering checksums
+
+# Roadmap
+
+Suggestions and requirements should be sent to <st...@gmail.com>.
+
+# License
+
+Copyright (c) 2013 Stephen Vickers
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+# Author
+
+Stephen Vickers <st...@gmail.com>