You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by bi...@apache.org on 2014/03/26 05:23:23 UTC

[06/15] This change set contains the odata javascript library V3. The version number is 1.1.2

http://git-wip-us.apache.org/repos/asf/olingo-odata3-js/blob/da25dc30/JSLib/src/store-memory.js
----------------------------------------------------------------------
diff --git a/JSLib/src/store-memory.js b/JSLib/src/store-memory.js
new file mode 100644
index 0000000..4f35090
--- /dev/null
+++ b/JSLib/src/store-memory.js
@@ -0,0 +1,231 @@
+// Copyright (c) Microsoft Open Technologies, Inc.  All rights reserved.
+// 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.
+
+// store-memory.js 
+
+(function (window, undefined) {
+
+    var datajs = window.datajs || {};
+
+    // Imports.
+    var throwErrorCallback = datajs.throwErrorCallback;
+    var delay = datajs.delay;
+
+    // CONTENT START
+
+    var MemoryStore = function (name) {
+        /// <summary>Constructor for store objects that use a sorted array as the underlying mechanism.</summary>
+        /// <param name="name" type="String">Store name.</param>
+
+        var holes = [];
+        var items = [];
+        var keys = {};
+
+        this.name = name;
+
+        var getErrorCallback = function (error) {
+            return error || this.defaultError;
+        };
+
+        var validateKeyInput = function (key, error) {
+            /// <summary>Validates that the specified key is not undefined, not null, and not an array</summary>
+            /// <param name="key">Key value.</param>
+            /// <param name="error" type="Function">Error callback.</param>
+            /// <returns type="Boolean">True if the key is valid. False if the key is invalid and the error callback has been queued for execution.</returns>
+
+            var messageString;
+
+            if (key instanceof Array) {
+                messageString = "Array of keys not supported";
+            }
+
+            if (key === undefined || key === null) {
+                messageString = "Invalid key";
+            }
+
+            if (messageString) {
+                delay(error, { message: messageString });
+                return false;
+            }
+            return true;
+        };
+
+        this.add = function (key, value, success, error) {
+            /// <summary>Adds a new value identified by a key to the store.</summary>
+            /// <param name="key" type="String">Key string.</param>
+            /// <param name="value">Value that is going to be added to the store.</param>
+            /// <param name="success" type="Function" optional="no">Callback for a successful add operation.</param>
+            /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+            /// <remarks>
+            ///    This method errors out if the store already contains the specified key.
+            /// </remarks>
+
+            error = getErrorCallback(error);
+
+            if (validateKeyInput(key, error)) {
+                if (!keys.hasOwnProperty(key)) {
+                    this.addOrUpdate(key, value, success, error);
+                } else {
+                    error({ message: "key already exists", key: key });
+                }
+            }
+        };
+
+        this.addOrUpdate = function (key, value, success, error) {
+            /// <summary>Adds or updates a value identified by a key to the store.</summary>
+            /// <param name="key" type="String">Key string.</param>
+            /// <param name="value">Value that is going to be added or updated to the store.</param>
+            /// <param name="success" type="Function" optional="no">Callback for a successful add or update operation.</param>
+            /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+            /// <remarks>
+            ///   This method will overwrite the key's current value if it already exists in the store; otherwise it simply adds the new key and value.
+            /// </remarks>
+
+            error = getErrorCallback(error);
+
+            if (validateKeyInput(key, error)) {
+                var index = keys[key];
+                if (index === undefined) {
+                    if (holes.length > 0) {
+                        index = holes.splice(0, 1);
+                    } else {
+                        index = items.length;
+                    }
+                }
+                items[index] = value;
+                keys[key] = index;
+                delay(success, key, value);
+            }
+        };
+
+        this.clear = function (success) {
+            /// <summary>Removes all the data associated with this store object.</summary>
+            /// <param name="success" type="Function" optional="no">Callback for a successful clear operation.</param>
+
+            items = [];
+            keys = {};
+            holes = [];
+
+            delay(success);
+        };
+
+        this.contains = function (key, success) {
+            /// <summary>Checks whether a key exists in the store.</summary>
+            /// <param name="key" type="String">Key string.</param>
+            /// <param name="success" type="Function" optional="no">Callback indicating whether the store contains the key or not.</param>
+
+            var contained = keys.hasOwnProperty(key);
+            delay(success, contained);
+        };
+
+        this.getAllKeys = function (success) {
+            /// <summary>Gets all the keys that exist in the store.</summary>
+            /// <param name="success" type="Function" optional="no">Callback for a successful get operation.</param>
+
+            var results = [];
+            for (var name in keys) {
+                results.push(name);
+            }
+            delay(success, results);
+        };
+
+        this.read = function (key, success, error) {
+            /// <summary>Reads the value associated to a key in the store.</summary>
+            /// <param name="key" type="String">Key string.</param>
+            /// <param name="success" type="Function" optional="no">Callback for a successful reads operation.</param>
+            /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+            error = getErrorCallback(error);
+
+            if (validateKeyInput(key, error)) {
+                var index = keys[key];
+                delay(success, key, items[index]);
+            }
+        };
+
+        this.remove = function (key, success, error) {
+            /// <summary>Removes a key and its value from the store.</summary>
+            /// <param name="key" type="String">Key string.</param>
+            /// <param name="success" type="Function" optional="no">Callback for a successful remove operation.</param>
+            /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+            error = getErrorCallback(error);
+
+            if (validateKeyInput(key, error)) {
+                var index = keys[key];
+                if (index !== undefined) {
+                    if (index === items.length - 1) {
+                        items.pop();
+                    } else {
+                        items[index] = undefined;
+                        holes.push(index);
+                    }
+                    delete keys[key];
+
+                    // The last item was removed, no need to keep track of any holes in the array.
+                    if (items.length === 0) {
+                        holes = [];
+                    }
+                }
+
+                delay(success);
+            }
+        };
+
+        this.update = function (key, value, success, error) {
+            /// <summary>Updates the value associated to a key in the store.</summary>
+            /// <param name="key" type="String">Key string.</param>
+            /// <param name="value">New value.</param>
+            /// <param name="success" type="Function" optional="no">Callback for a successful update operation.</param>
+            /// <param name="error" type="Function" optional="yes">Callback for handling errors. If not specified then store.defaultError is invoked.</param>
+            /// <remarks>
+            ///    This method errors out if the specified key is not found in the store.
+            /// </remarks>
+
+            error = getErrorCallback(error);
+            if (validateKeyInput(key, error)) {
+                if (keys.hasOwnProperty(key)) {
+                    this.addOrUpdate(key, value, success, error);
+                } else {
+                    error({ message: "key not found", key: key });
+                }
+            }
+        };
+    };
+
+    MemoryStore.create = function (name) {
+        /// <summary>Creates a store object that uses memory storage as its underlying mechanism.</summary>
+        /// <param name="name" type="String">Store name.</param>
+        /// <returns type="Object">Store object.</returns>
+        return new MemoryStore(name);
+    };
+
+    MemoryStore.isSupported = function () {
+        /// <summary>Checks whether the underlying mechanism for this kind of store objects is supported by the browser.</summary>
+        /// <returns type="Boolean">True if the mechanism is supported by the browser; otherwise false.</returns>
+        return true;
+    };
+
+    MemoryStore.prototype.close = function () {
+        /// <summary>This function does nothing in MemoryStore as it does not have a connection model.</summary>
+    };
+
+    MemoryStore.prototype.defaultError = throwErrorCallback;
+
+    /// <summary>Identifies the underlying mechanism used by the store.</summary>
+    MemoryStore.prototype.mechanism = "memory";
+
+    // DATAJS INTERNAL START
+    datajs.MemoryStore = MemoryStore;
+    // DATAJS INTERNAL END
+
+    // CONTENT END
+})(this);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata3-js/blob/da25dc30/JSLib/src/store.js
----------------------------------------------------------------------
diff --git a/JSLib/src/store.js b/JSLib/src/store.js
new file mode 100644
index 0000000..688e88e
--- /dev/null
+++ b/JSLib/src/store.js
@@ -0,0 +1,61 @@
+// Copyright (c) Microsoft Open Technologies, Inc.  All rights reserved.
+// 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.
+
+// store.js 
+
+(function (window, undefined) {
+   
+    var datajs = window.datajs || {};
+
+    var DomStore = datajs.DomStore;
+    var IndexedDBStore = datajs.IndexedDBStore;
+    var MemoryStore = datajs.MemoryStore;
+
+    // CONTENT START
+
+    var mechanisms = {
+        indexeddb: IndexedDBStore,
+        dom: DomStore,
+        memory: MemoryStore
+    };
+
+    datajs.defaultStoreMechanism = "best";
+
+    datajs.createStore = function (name, mechanism) {
+        /// <summary>Creates a new store object.</summary>
+        /// <param name="name" type="String">Store name.</param>
+        /// <param name="mechanism" type="String" optional="true">A specific mechanism to use (defaults to best, can be "best", "dom", "indexeddb", "webdb").</param>
+        /// <returns type="Object">Store object.</returns>
+
+        if (!mechanism) {
+            mechanism = datajs.defaultStoreMechanism;
+        }
+
+        if (mechanism === "best") {
+            mechanism = (DomStore.isSupported()) ? "dom" : "memory";
+        }
+
+        var factory = mechanisms[mechanism];
+        if (factory) {
+            return factory.create(name);
+        }
+
+        throw { message: "Failed to create store", name: name, mechanism: mechanism };
+    };
+
+    // DATAJS INTERNAL START
+    datajs.mechanisms = mechanisms;
+    // DATAJS INTERNAL END
+
+    // CONTENT END
+})(this);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata3-js/blob/da25dc30/JSLib/src/utils.js
----------------------------------------------------------------------
diff --git a/JSLib/src/utils.js b/JSLib/src/utils.js
new file mode 100644
index 0000000..3dd3a49
--- /dev/null
+++ b/JSLib/src/utils.js
@@ -0,0 +1,490 @@
+// Copyright (c) Microsoft Open Technologies, Inc.  All rights reserved.
+// 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.
+
+// utils.js
+
+(function (window, undefined) {
+
+    var datajs = window.datajs || {};
+
+    // CONTENT START
+
+    var activeXObject = function (progId) {
+        /// <summary>Creates a new ActiveXObject from the given progId.</summary>
+        /// <param name="progId" type="String" mayBeNull="false" optional="false">
+        ///    ProgId string of the desired ActiveXObject.
+        /// </param>
+        /// <remarks>
+        ///    This function throws whatever exception might occur during the creation
+        ///    of the ActiveXObject.
+        /// </remarks>
+        /// <returns type="Object">
+        ///     The ActiveXObject instance. Null if ActiveX is not supported by the
+        ///     browser.
+        /// </returns>
+        if (window.ActiveXObject) {
+            return new window.ActiveXObject(progId);
+        }
+        return null;
+    };
+
+    var assigned = function (value) {
+        /// <summary>Checks whether the specified value is different from null and undefined.</summary>
+        /// <param name="value" mayBeNull="true" optional="true">Value to check.</param>
+        /// <returns type="Boolean">true if the value is assigned; false otherwise.</returns>
+        return value !== null && value !== undefined;
+    };
+
+    var contains = function (arr, item) {
+        /// <summary>Checks whether the specified item is in the array.</summary>
+        /// <param name="arr" type="Array" optional="false" mayBeNull="false">Array to check in.</param>
+        /// <param name="item">Item to look for.</param>
+        /// <returns type="Boolean">true if the item is contained, false otherwise.</returns>
+
+        var i, len;
+        for (i = 0, len = arr.length; i < len; i++) {
+            if (arr[i] === item) {
+                return true;
+            }
+        }
+
+        return false;
+    };
+
+    var defined = function (a, b) {
+        /// <summary>Given two values, picks the first one that is not undefined.</summary>
+        /// <param name="a">First value.</param>
+        /// <param name="b">Second value.</param>
+        /// <returns>a if it's a defined value; else b.</returns>
+        return (a !== undefined) ? a : b;
+    };
+
+    var delay = function (callback) {
+        /// <summary>Delays the invocation of the specified function until execution unwinds.</summary>
+        /// <param name="callback" type="Function">Callback function.</param>
+        if (arguments.length === 1) {
+            window.setTimeout(callback, 0);
+            return;
+        }
+
+        var args = Array.prototype.slice.call(arguments, 1);
+        window.setTimeout(function () {
+            callback.apply(this, args);
+        }, 0);
+    };
+
+    // DATAJS INTERNAL START
+    var djsassert = function (condition, message, data) {
+        /// <summary>Throws an exception in case that a condition evaluates to false.</summary>
+        /// <param name="condition" type="Boolean">Condition to evaluate.</param>
+        /// <param name="message" type="String">Message explaining the assertion.</param>
+        /// <param name="data" type="Object">Additional data to be included in the exception.</param>
+
+        if (!condition) {
+            throw { message: "Assert fired: " + message, data: data };
+        };
+    };
+    // DATAJS INTERNAL END
+
+    var extend = function (target, values) {
+        /// <summary>Extends the target with the specified values.</summary>
+        /// <param name="target" type="Object">Object to add properties to.</param>
+        /// <param name="values" type="Object">Object with properties to add into target.</param>
+        /// <returns type="Object">The target object.</returns>
+
+        for (var name in values) {
+            target[name] = values[name];
+        }
+
+        return target;
+    };
+
+    var find = function (arr, callback) {
+        /// <summary>Returns the first item in the array that makes the callback function true.</summary>
+        /// <param name="arr" type="Array" optional="false" mayBeNull="true">Array to check in.</param>
+        /// <param name="callback" type="Function">Callback function to invoke once per item in the array.</param>
+        /// <returns>The first item that makes the callback return true; null otherwise or if the array is null.</returns>
+
+        if (arr) {
+            var i, len;
+            for (i = 0, len = arr.length; i < len; i++) {
+                if (callback(arr[i])) {
+                    return arr[i];
+                }
+            }
+        }
+        return null;
+    };
+
+    var isArray = function (value) {
+        /// <summary>Checks whether the specified value is an array object.</summary>
+        /// <param name="value">Value to check.</param>
+        /// <returns type="Boolean">true if the value is an array object; false otherwise.</returns>
+
+        return Object.prototype.toString.call(value) === "[object Array]";
+    };
+
+    var isDate = function (value) {
+        /// <summary>Checks whether the specified value is a Date object.</summary>
+        /// <param name="value">Value to check.</param>
+        /// <returns type="Boolean">true if the value is a Date object; false otherwise.</returns>
+
+        return Object.prototype.toString.call(value) === "[object Date]";
+    };
+
+    var isObject = function (value) {
+        /// <summary>Tests whether a value is an object.</summary>
+        /// <param name="value">Value to test.</param>
+        /// <remarks>
+        ///     Per javascript rules, null and array values are objects and will cause this function to return true.
+        /// </remarks>
+        /// <returns type="Boolean">True is the value is an object; false otherwise.</returns>
+
+        return typeof value === "object";
+    };
+
+    var parseInt10 = function (value) {
+        /// <summary>Parses a value in base 10.</summary>
+        /// <param name="value" type="String">String value to parse.</param>
+        /// <returns type="Number">The parsed value, NaN if not a valid value.</returns>
+
+        return parseInt(value, 10);
+    };
+
+    var renameProperty = function (obj, oldName, newName) {
+        /// <summary>Renames a property in an object.</summary>
+        /// <param name="obj" type="Object">Object in which the property will be renamed.</param>
+        /// <param name="oldName" type="String">Name of the property that will be renamed.</param>
+        /// <param name="newName" type="String">New name of the property.</param>
+        /// <remarks>
+        ///    This function will not do anything if the object doesn't own a property with the specified old name.
+        /// </remarks>
+
+        if (obj.hasOwnProperty(oldName)) {
+            obj[newName] = obj[oldName];
+            delete obj[oldName];
+        }
+    };
+
+    var throwErrorCallback = function (error) {
+        /// <summary>Default error handler.</summary>
+        /// <param name="error" type="Object">Error to handle.</param>
+        throw error;
+    };
+
+    var trimString = function (str) {
+        /// <summary>Removes leading and trailing whitespaces from a string.</summary>
+        /// <param name="str" type="String" optional="false" mayBeNull="false">String to trim</param>
+        /// <returns type="String">The string with no leading or trailing whitespace.</returns>
+
+        if (str.trim) {
+            return str.trim();
+        }
+
+        return str.replace(/^\s+|\s+$/g, '');
+    };
+
+    var undefinedDefault = function (value, defaultValue) {
+        /// <summary>Returns a default value in place of undefined.</summary>
+        /// <param name="value" mayBeNull="true" optional="true">Value to check.</param>
+        /// <param name="defaultValue">Value to return if value is undefined.</param>
+        /// <returns>value if it's defined; defaultValue otherwise.</returns>
+        /// <remarks>
+        /// This should only be used for cases where falsy values are valid;
+        /// otherwise the pattern should be 'x = (value) ? value : defaultValue;'.
+        /// </remarks>
+        return (value !== undefined) ? value : defaultValue;
+    };
+
+    // Regular expression that splits a uri into its components:
+    // 0 - is the matched string.
+    // 1 - is the scheme.
+    // 2 - is the authority.
+    // 3 - is the path.
+    // 4 - is the query.
+    // 5 - is the fragment.
+    var uriRegEx = /^([^:\/?#]+:)?(\/\/[^\/?#]*)?([^?#:]+)?(\?[^#]*)?(#.*)?/;
+    var uriPartNames = ["scheme", "authority", "path", "query", "fragment"];
+
+    var getURIInfo = function (uri) {
+        /// <summary>Gets information about the components of the specified URI.</summary>
+        /// <param name="uri" type="String">URI to get information from.</param>
+        /// <returns type="Object">
+        /// An object with an isAbsolute flag and part names (scheme, authority, etc.) if available.
+        /// </returns>
+
+        var result = { isAbsolute: false };
+
+        if (uri) {
+            var matches = uriRegEx.exec(uri);
+            if (matches) {
+                var i, len;
+                for (i = 0, len = uriPartNames.length; i < len; i++) {
+                    if (matches[i + 1]) {
+                        result[uriPartNames[i]] = matches[i + 1];
+                    }
+                }
+            }
+            if (result.scheme) {
+                result.isAbsolute = true;
+            }
+        }
+
+        return result;
+    };
+
+    var getURIFromInfo = function (uriInfo) {
+        /// <summary>Builds a URI string from its components.</summary>
+        /// <param name="uriInfo" type="Object"> An object with uri parts (scheme, authority, etc.).</param>
+        /// <returns type="String">URI string.</returns>
+
+        return "".concat(
+            uriInfo.scheme || "",
+            uriInfo.authority || "",
+            uriInfo.path || "",
+            uriInfo.query || "",
+            uriInfo.fragment || "");
+    };
+
+    // Regular expression that splits a uri authority into its subcomponents:
+    // 0 - is the matched string.
+    // 1 - is the userinfo subcomponent.
+    // 2 - is the host subcomponent.
+    // 3 - is the port component.
+    var uriAuthorityRegEx = /^\/{0,2}(?:([^@]*)@)?([^:]+)(?::{1}(\d+))?/;
+
+    // Regular expression that matches percentage enconded octects (i.e %20 or %3A);
+    var pctEncodingRegEx = /%[0-9A-F]{2}/ig;
+
+    var normalizeURICase = function (uri) {
+        /// <summary>Normalizes the casing of a URI.</summary>
+        /// <param name="uri" type="String">URI to normalize, absolute or relative.</param>
+        /// <returns type="String">The URI normalized to lower case.</returns>
+
+        var uriInfo = getURIInfo(uri);
+        var scheme = uriInfo.scheme;
+        var authority = uriInfo.authority;
+
+        if (scheme) {
+            uriInfo.scheme = scheme.toLowerCase();
+            if (authority) {
+                var matches = uriAuthorityRegEx.exec(authority);
+                if (matches) {
+                    uriInfo.authority = "//" +
+                    (matches[1] ? matches[1] + "@" : "") +
+                    (matches[2].toLowerCase()) +
+                    (matches[3] ? ":" + matches[3] : "");
+                }
+            }
+        }
+
+        uri = getURIFromInfo(uriInfo);
+
+        return uri.replace(pctEncodingRegEx, function (str) {
+            return str.toLowerCase();
+        });
+    };
+
+    var normalizeURI = function (uri, base) {
+        /// <summary>Normalizes a possibly relative URI with a base URI.</summary>
+        /// <param name="uri" type="String">URI to normalize, absolute or relative.</param>
+        /// <param name="base" type="String" mayBeNull="true">Base URI to compose with.</param>
+        /// <returns type="String">The composed URI if relative; the original one if absolute.</returns>
+
+        if (!base) {
+            return uri;
+        }
+
+        var uriInfo = getURIInfo(uri);
+        if (uriInfo.isAbsolute) {
+            return uri;
+        }
+
+        var baseInfo = getURIInfo(base);
+        var normInfo = {};
+        var path;
+
+        if (uriInfo.authority) {
+            normInfo.authority = uriInfo.authority;
+            path = uriInfo.path;
+            normInfo.query = uriInfo.query;
+        } else {
+            if (!uriInfo.path) {
+                path = baseInfo.path;
+                normInfo.query = uriInfo.query || baseInfo.query;
+            } else {
+                if (uriInfo.path.charAt(0) === '/') {
+                    path = uriInfo.path;
+                } else {
+                    path = mergeUriPathWithBase(uriInfo.path, baseInfo.path);
+                }
+                normInfo.query = uriInfo.query;
+            }
+            normInfo.authority = baseInfo.authority;
+        }
+
+        normInfo.path = removeDotsFromPath(path);
+
+        normInfo.scheme = baseInfo.scheme;
+        normInfo.fragment = uriInfo.fragment;
+
+        return getURIFromInfo(normInfo);
+    };
+
+    var mergeUriPathWithBase = function (uriPath, basePath) {
+        /// <summary>Merges the path of a relative URI and a base URI.</summary>
+        /// <param name="uriPath" type="String>Relative URI path.</param>
+        /// <param name="basePath" type="String">Base URI path.</param>
+        /// <returns type="String">A string with the merged path.</returns>
+
+        var path = "/";
+        var end;
+
+        if (basePath) {
+            end = basePath.lastIndexOf("/");
+            path = basePath.substring(0, end);
+
+            if (path.charAt(path.length - 1) !== "/") {
+                path = path + "/";
+            }
+        }
+
+        return path + uriPath;
+    };
+
+    var removeDotsFromPath = function (path) {
+        /// <summary>Removes the special folders . and .. from a URI's path.</summary>
+        /// <param name="path" type="string">URI path component.</param>
+        /// <returns type="String">Path without any . and .. folders.</returns>
+
+        var result = "";
+        var segment = "";
+        var end;
+
+        while (path) {
+            if (path.indexOf("..") === 0 || path.indexOf(".") === 0) {
+                path = path.replace(/^\.\.?\/?/g, "");
+            } else if (path.indexOf("/..") === 0) {
+                path = path.replace(/^\/\..\/?/g, "/");
+                end = result.lastIndexOf("/");
+                if (end === -1) {
+                    result = "";
+                } else {
+                    result = result.substring(0, end);
+                }
+            } else if (path.indexOf("/.") === 0) {
+                path = path.replace(/^\/\.\/?/g, "/");
+            } else {
+                segment = path;
+                end = path.indexOf("/", 1);
+                if (end !== -1) {
+                    segment = path.substring(0, end);
+                }
+                result = result + segment;
+                path = path.replace(segment, "");
+            }
+        }
+        return result;
+    };
+
+    var convertByteArrayToHexString = function (str) {
+        var arr = [];
+        if (window.atob === undefined) {
+            arr = decodeBase64(str);
+        } else {
+            var binaryStr = window.atob(str);
+            for (var i = 0; i < binaryStr.length; i++) {
+                arr.push(binaryStr.charCodeAt(i));
+            }
+        }
+        var hexValue = "";
+        var hexValues = "0123456789ABCDEF";
+        for (var j = 0; j < arr.length; j++) {
+            var t = arr[j];
+            hexValue += hexValues[t >> 4];
+            hexValue += hexValues[t & 0x0F];
+        }
+        return hexValue;
+    };
+
+    var decodeBase64 = function (str) {
+        var binaryString = "";
+        for (var i = 0; i < str.length; i++) {
+            var base65IndexValue = getBase64IndexValue(str[i]);
+            var binaryValue = "";
+            if (base65IndexValue !== null) {
+                binaryValue = base65IndexValue.toString(2);
+                binaryString += addBase64Padding(binaryValue);
+            }
+        }
+        var byteArray = [];
+        var numberOfBytes = parseInt(binaryString.length / 8, 10);
+        for (i = 0; i < numberOfBytes; i++) {
+            var intValue = parseInt(binaryString.substring(i * 8, (i + 1) * 8), 2);
+            byteArray.push(intValue);
+        }
+        return byteArray;
+    };
+
+    var getBase64IndexValue = function (character) {
+        var asciiCode = character.charCodeAt(0);
+        var asciiOfA = 65;
+        var differenceBetweenZanda = 6;
+        if (asciiCode >= 65 && asciiCode <= 90) {           // between "A" and "Z" inclusive
+            return asciiCode - asciiOfA;
+        } else if (asciiCode >= 97 && asciiCode <= 122) {   // between 'a' and 'z' inclusive
+            return asciiCode - asciiOfA - differenceBetweenZanda;
+        } else if (asciiCode >= 48 && asciiCode <= 57) {    // between '0' and '9' inclusive
+            return asciiCode + 4;
+        } else if (character == "+") {
+            return 62;
+        } else if (character == "/") {
+            return 63;
+        } else {
+            return null;
+        }
+    };
+
+    var addBase64Padding = function (binaryString) {
+        while (binaryString.length < 6) {
+            binaryString = "0" + binaryString;
+        }
+        return binaryString;
+    };
+    // DATAJS INTERNAL START
+
+    datajs.activeXObject = activeXObject;
+    datajs.assigned = assigned;
+    datajs.contains = contains;
+    datajs.defined = defined;
+    datajs.delay = delay;
+    datajs.djsassert = djsassert;
+    datajs.extend = extend;
+    datajs.find = find;
+    datajs.getURIInfo = getURIInfo;
+    datajs.isArray = isArray;
+    datajs.isDate = isDate;
+    datajs.isObject = isObject;
+    datajs.normalizeURI = normalizeURI;
+    datajs.normalizeURICase = normalizeURICase;
+    datajs.parseInt10 = parseInt10;
+    datajs.renameProperty = renameProperty;
+    datajs.throwErrorCallback = throwErrorCallback;
+    datajs.trimString = trimString;
+    datajs.undefinedDefault = undefinedDefault;
+    datajs.decodeBase64 = decodeBase64;
+    datajs.convertByteArrayToHexString = convertByteArrayToHexString;
+    // DATAJS INTERNAL END
+
+    // CONTENT END
+})(this);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata3-js/blob/da25dc30/JSLib/src/xml.js
----------------------------------------------------------------------
diff --git a/JSLib/src/xml.js b/JSLib/src/xml.js
new file mode 100644
index 0000000..895a4c7
--- /dev/null
+++ b/JSLib/src/xml.js
@@ -0,0 +1,824 @@
+// Copyright (c) Microsoft Open Technologies, Inc.  All rights reserved.
+// 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.
+
+// xml.js
+
+(function (window, undefined) {
+
+    var datajs = window.datajs;
+
+    var activeXObject = datajs.activeXObject;
+    var djsassert = datajs.djsassert;
+    var extend = datajs.extend;
+    var isArray = datajs.isArray;
+    var isObject = datajs.isObject;
+    var normalizeURI = datajs.normalizeURI;
+
+    // CONTENT START
+
+    // URI prefixes to generate smaller code.
+    var http = "http://";
+    var w3org = http + "www.w3.org/";               // http://www.w3.org/
+
+    var xhtmlNS = w3org + "1999/xhtml";             // http://www.w3.org/1999/xhtml
+    var xmlnsNS = w3org + "2000/xmlns/";            // http://www.w3.org/2000/xmlns/
+    var xmlNS = w3org + "XML/1998/namespace";       // http://www.w3.org/XML/1998/namespace
+
+    var mozillaParserErroNS = http + "www.mozilla.org/newlayout/xml/parsererror.xml";
+
+    var hasLeadingOrTrailingWhitespace = function (text) {
+        /// <summary>Checks whether the specified string has leading or trailing spaces.</summary>
+        /// <param name="text" type="String">String to check.</param>
+        /// <returns type="Boolean">true if text has any leading or trailing whitespace; false otherwise.</returns>
+
+        var re = /(^\s)|(\s$)/;
+        return re.test(text);
+    };
+
+    var isWhitespace = function (text) {
+        /// <summary>Determines whether the specified text is empty or whitespace.</summary>
+        /// <param name="text" type="String">Value to inspect.</param>
+        /// <returns type="Boolean">true if the text value is empty or all whitespace; false otherwise.</returns>
+
+        var ws = /^\s*$/;
+        return text === null || ws.test(text);
+    };
+
+    var isWhitespacePreserveContext = function (domElement) {
+        /// <summary>Determines whether the specified element has xml:space='preserve' applied.</summary>
+        /// <param name="domElement">Element to inspect.</param>
+        /// <returns type="Boolean">Whether xml:space='preserve' is in effect.</returns>
+
+        while (domElement !== null && domElement.nodeType === 1) {
+            var val = xmlAttributeValue(domElement, "space", xmlNS);
+            if (val === "preserve") {
+                return true;
+            } else if (val === "default") {
+                break;
+            } else {
+                domElement = domElement.parentNode;
+            }
+        }
+
+        return false;
+    };
+
+    var isXmlNSDeclaration = function (domAttribute) {
+        /// <summary>Determines whether the attribute is a XML namespace declaration.</summary>
+        /// <param name="domAttribute">Element to inspect.</param>
+        /// <returns type="Boolean">
+        ///    True if the attribute is a namespace declaration (its name is 'xmlns' or starts with 'xmlns:'; false otherwise.
+        /// </returns>
+
+        var nodeName = domAttribute.nodeName;
+        return nodeName == "xmlns" || nodeName.indexOf("xmlns:") === 0;
+    };
+
+    var safeSetProperty = function (obj, name, value) {
+        /// <summary>Safely set as property in an object by invoking obj.setProperty.</summary>
+        /// <param name="obj">Object that exposes a setProperty method.</param>
+        /// <param name="name" type="String" mayBeNull="false">Property name.</param>
+        /// <param name="value">Property value.</param>
+
+        try {
+            obj.setProperty(name, value);
+        } catch (_) { }
+    };
+
+    var msXmlDom3 = function () {
+        /// <summary>Creates an configures new MSXML 3.0 ActiveX object.</summary>
+        /// <remakrs>
+        ///    This function throws any exception that occurs during the creation
+        ///    of the MSXML 3.0 ActiveX object.
+        /// <returns type="Object">New MSXML 3.0 ActiveX object.</returns>
+
+        var msxml3 = activeXObject("Msxml2.DOMDocument.3.0");
+        if (msxml3) {
+            safeSetProperty(msxml3, "ProhibitDTD", true);
+            safeSetProperty(msxml3, "MaxElementDepth", 256);
+            safeSetProperty(msxml3, "AllowDocumentFunction", false);
+            safeSetProperty(msxml3, "AllowXsltScript", false);
+        }
+        return msxml3;
+    };
+
+    var msXmlDom = function () {
+        /// <summary>Creates an configures new MSXML 6.0 or MSXML 3.0 ActiveX object.</summary>
+        /// <remakrs>
+        ///    This function will try to create a new MSXML 6.0 ActiveX object. If it fails then
+        ///    it will fallback to create a new MSXML 3.0 ActiveX object. Any exception that
+        ///    happens during the creation of the MSXML 6.0 will be handled by the function while
+        ///    the ones that happend during the creation of the MSXML 3.0 will be thrown.
+        /// <returns type="Object">New MSXML 3.0 ActiveX object.</returns>
+
+        try {
+            var msxml = activeXObject("Msxml2.DOMDocument.6.0");
+            if (msxml) {
+                msxml.async = true;
+            }
+            return msxml;
+        } catch (_) {
+            return msXmlDom3();
+        }
+    };
+
+    var msXmlParse = function (text) {
+        /// <summary>Parses an XML string using the MSXML DOM.</summary>
+        /// <remakrs>
+        ///    This function throws any exception that occurs during the creation
+        ///    of the MSXML ActiveX object.  It also will throw an exception
+        ///    in case of a parsing error.
+        /// <returns type="Object">New MSXML DOMDocument node representing the parsed XML string.</returns>
+
+        var dom = msXmlDom();
+        if (!dom) {
+            return null;
+        }
+
+        dom.loadXML(text);
+        var parseError = dom.parseError;
+        if (parseError.errorCode !== 0) {
+            xmlThrowParserError(parseError.reason, parseError.srcText, text);
+        }
+        return dom;
+    };
+
+    var xmlThrowParserError = function (exceptionOrReason, srcText, errorXmlText) {
+        /// <summary>Throws a new exception containing XML parsing error information.</summary>
+        /// <param name="exceptionOrReason">
+        ///    String indicatin the reason of the parsing failure or
+        ///    Object detailing the parsing error.
+        /// </param>
+        /// <param name="srcText" type="String">
+        ///    String indicating the part of the XML string that caused the parsing error.
+        /// </param>
+        /// <param name="errorXmlText" type="String">XML string for wich the parsing failed.</param>
+
+        if (typeof exceptionOrReason === "string") {
+            exceptionOrReason = { message: exceptionOrReason };
+        }
+        throw extend(exceptionOrReason, { srcText: srcText || "", errorXmlText: errorXmlText || "" });
+    };
+
+    var xmlParse = function (text) {
+        /// <summary>Returns an XML DOM document from the specified text.</summary>
+        /// <param name="text" type="String">Document text.</param>
+        /// <returns>XML DOM document.</returns>
+        /// <remarks>This function will throw an exception in case of a parse error.</remarks>
+
+        var domParser = window.DOMParser && new window.DOMParser();
+        var dom;
+
+        if (!domParser) {
+            dom = msXmlParse(text);
+            if (!dom) {
+                xmlThrowParserError("XML DOM parser not supported");
+            }
+            return dom;
+        }
+
+        try {
+            dom = domParser.parseFromString(text, "text/xml");
+        } catch (e) {
+            xmlThrowParserError(e, "", text);
+        }
+
+        var element = dom.documentElement;
+        var nsURI = element.namespaceURI;
+        var localName = xmlLocalName(element);
+
+        // Firefox reports errors by returing the DOM for an xml document describing the problem.
+        if (localName === "parsererror" && nsURI === mozillaParserErroNS) {
+            var srcTextElement = xmlFirstChildElement(element, mozillaParserErroNS, "sourcetext");
+            var srcText = srcTextElement ? xmlNodeValue(srcTextElement) : "";
+            xmlThrowParserError(xmlInnerText(element) || "", srcText, text);
+        }
+
+        // Chrome (and maybe other webkit based browsers) report errors by injecting a header with an error message.
+        // The error may be localized, so instead we simply check for a header as the
+        // top element or descendant child of the document.
+        if (localName === "h3" && nsURI === xhtmlNS || xmlFirstDescendantElement(element, xhtmlNS, "h3")) {
+            var reason = "";
+            var siblings = [];
+            var cursor = element.firstChild;
+            while (cursor) {
+                if (cursor.nodeType === 1) {
+                    reason += xmlInnerText(cursor) || "";
+                }
+                siblings.push(cursor.nextSibling);
+                cursor = cursor.firstChild || siblings.shift();
+            }
+            reason += xmlInnerText(element) || "";
+            xmlThrowParserError(reason, "", text);
+        }
+
+        return dom;
+    };
+
+    var xmlQualifiedName = function (prefix, name) {
+        /// <summary>Builds a XML qualified name string in the form of "prefix:name".</summary>
+        /// <param name="prefix" type="String" maybeNull="true">Prefix string.</param>
+        /// <param name="name" type="String">Name string to qualify with the prefix.</param>
+        /// <returns type="String">Qualified name.</returns>
+
+        return prefix ? prefix + ":" + name : name;
+    };
+
+    var xmlAppendText = function (domNode, textNode) {
+        /// <summary>Appends a text node into the specified DOM element node.</summary>
+        /// <param name="domNode">DOM node for the element.</param>
+        /// <param name="text" type="String" mayBeNull="false">Text to append as a child of element.</param>
+        if (hasLeadingOrTrailingWhitespace(textNode.data)) {
+            var attr = xmlAttributeNode(domNode, xmlNS, "space");
+            if (!attr) {
+                attr = xmlNewAttribute(domNode.ownerDocument, xmlNS, xmlQualifiedName("xml", "space"));
+                xmlAppendChild(domNode, attr);
+            }
+            attr.value = "preserve";
+        }
+        domNode.appendChild(textNode);
+        return domNode;
+    };
+
+    var xmlAttributes = function (element, onAttributeCallback) {
+        /// <summary>Iterates through the XML element's attributes and invokes the callback function for each one.</summary>
+        /// <param name="element">Wrapped element to iterate over.</param>
+        /// <param name="onAttributeCallback" type="Function">Callback function to invoke with wrapped attribute nodes.</param>
+
+        var attributes = element.attributes;
+        var i, len;
+        for (i = 0, len = attributes.length; i < len; i++) {
+            onAttributeCallback(attributes.item(i));
+        }
+    };
+
+    var xmlAttributeValue = function (domNode, localName, nsURI) {
+        /// <summary>Returns the value of a DOM element's attribute.</summary>
+        /// <param name="domNode">DOM node for the owning element.</param>
+        /// <param name="localName" type="String">Local name of the attribute.</param>
+        /// <param name="nsURI" type="String">Namespace URI of the attribute.</param>
+        /// <returns type="String" maybeNull="true">The attribute value, null if not found.</returns>
+
+        var attribute = xmlAttributeNode(domNode, localName, nsURI);
+        return attribute ? xmlNodeValue(attribute) : null;
+    };
+
+    var xmlAttributeNode = function (domNode, localName, nsURI) {
+        /// <summary>Gets an attribute node from a DOM element.</summary>
+        /// <param name="domNode">DOM node for the owning element.</param>
+        /// <param name="localName" type="String">Local name of the attribute.</param>
+        /// <param name="nsURI" type="String">Namespace URI of the attribute.</param>
+        /// <returns>The attribute node, null if not found.</returns>
+
+        var attributes = domNode.attributes;
+        if (attributes.getNamedItemNS) {
+            return attributes.getNamedItemNS(nsURI || null, localName);
+        }
+
+        return attributes.getQualifiedItem(localName, nsURI) || null;
+    };
+
+    var xmlBaseURI = function (domNode, baseURI) {
+        /// <summary>Gets the value of the xml:base attribute on the specified element.</summary>
+        /// <param name="domNode">Element to get xml:base attribute value from.</param>
+        /// <param name="baseURI" mayBeNull="true" optional="true">Base URI used to normalize the value of the xml:base attribute.</param>
+        /// <returns type="String">Value of the xml:base attribute if found; the baseURI or null otherwise.</returns>
+
+        var base = xmlAttributeNode(domNode, "base", xmlNS);
+        return (base ? normalizeURI(base.value, baseURI) : baseURI) || null;
+    };
+
+
+    var xmlChildElements = function (domNode, onElementCallback) {
+        /// <summary>Iterates through the XML element's child DOM elements and invokes the callback function for each one.</summary>
+        /// <param name="element">DOM Node containing the DOM elements to iterate over.</param>
+        /// <param name="onElementCallback" type="Function">Callback function to invoke for each child DOM element.</param>
+
+        xmlTraverse(domNode, /*recursive*/false, function (child) {
+            if (child.nodeType === 1) {
+                onElementCallback(child);
+            }
+            // continue traversing.
+            return true;
+        });
+    };
+
+    var xmlFindElementByPath = function (root, namespaceURI, path) {
+        /// <summary>Gets the descendant element under root that corresponds to the specified path and namespace URI.</summary>
+        /// <param name="root">DOM element node from which to get the descendant element.</param>
+        /// <param name="namespaceURI" type="String">The namespace URI of the element to match.</param>
+        /// <param name="path" type="String">Path to the desired descendant element.</param>
+        /// <returns>The element specified by path and namespace URI.</returns>
+        /// <remarks>
+        ///     All the elements in the path are matched against namespaceURI.
+        ///     The function will stop searching on the first element that doesn't match the namespace and the path.
+        /// </remarks>
+
+        var parts = path.split("/");
+        var i, len;
+        for (i = 0, len = parts.length; i < len; i++) {
+            root = root && xmlFirstChildElement(root, namespaceURI, parts[i]);
+        }
+        return root || null;
+    };
+
+    var xmlFindNodeByPath = function (root, namespaceURI, path) {
+        /// <summary>Gets the DOM element or DOM attribute node under root that corresponds to the specified path and namespace URI.</summary>
+        /// <param name="root">DOM element node from which to get the descendant node.</param>
+        /// <param name="namespaceURI" type="String">The namespace URI of the node to match.</param>
+        /// <param name="path" type="String">Path to the desired descendant node.</param>
+        /// <returns>The node specified by path and namespace URI.</returns>
+        /// <remarks>
+        ///     This function will traverse the path and match each node associated to a path segement against the namespace URI.
+        ///     The traversal stops when the whole path has been exahusted or a node that doesn't belogong the specified namespace is encountered.
+        ///
+        ///     The last segment of the path may be decorated with a starting @ character to indicate that the desired node is a DOM attribute.
+        /// </remarks>
+
+        var lastSegmentStart = path.lastIndexOf("/");
+        var nodePath = path.substring(lastSegmentStart + 1);
+        var parentPath = path.substring(0, lastSegmentStart);
+
+        var node = parentPath ? xmlFindElementByPath(root, namespaceURI, parentPath) : root;
+        if (node) {
+            if (nodePath.charAt(0) === "@") {
+                return xmlAttributeNode(node, nodePath.substring(1), namespaceURI);
+            }
+            return xmlFirstChildElement(node, namespaceURI, nodePath);
+        }
+        return null;
+    };
+
+    var xmlFirstChildElement = function (domNode, namespaceURI, localName) {
+        /// <summary>Returns the first child DOM element under the specified DOM node that matches the specified namespace URI and local name.</summary>
+        /// <param name="domNode">DOM node from which the child DOM element is going to be retrieved.</param>
+        /// <param name="namespaceURI" type="String" optional="true">The namespace URI of the element to match.</param>
+        /// <param name="localName" type="String" optional="true">Name of the element to match.</param>
+        /// <returns>The node's first child DOM element that matches the specified namespace URI and local name; null otherwise.</returns>
+
+        return xmlFirstElementMaybeRecursive(domNode, namespaceURI, localName, /*recursive*/false);
+    };
+
+    var xmlFirstDescendantElement = function (domNode, namespaceURI, localName) {
+        /// <summary>Returns the first descendant DOM element under the specified DOM node that matches the specified namespace URI and local name.</summary>
+        /// <param name="domNode">DOM node from which the descendant DOM element is going to be retrieved.</param>
+        /// <param name="namespaceURI" type="String" optional="true">The namespace URI of the element to match.</param>
+        /// <param name="localName" type="String" optional="true">Name of the element to match.</param>
+        /// <returns>The node's first descendant DOM element that matches the specified namespace URI and local name; null otherwise.</returns>
+
+        if (domNode.getElementsByTagNameNS) {
+            var result = domNode.getElementsByTagNameNS(namespaceURI, localName);
+            return result.length > 0 ? result[0] : null;
+        }
+        return xmlFirstElementMaybeRecursive(domNode, namespaceURI, localName, /*recursive*/true);
+    };
+
+    var xmlFirstElementMaybeRecursive = function (domNode, namespaceURI, localName, recursive) {
+        /// <summary>Returns the first descendant DOM element under the specified DOM node that matches the specified namespace URI and local name.</summary>
+        /// <param name="domNode">DOM node from which the descendant DOM element is going to be retrieved.</param>
+        /// <param name="namespaceURI" type="String" optional="true">The namespace URI of the element to match.</param>
+        /// <param name="localName" type="String" optional="true">Name of the element to match.</param>
+        /// <param name="recursive" type="Boolean">
+        ///     True if the search should include all the descendants of the DOM node.
+        ///     False if the search should be scoped only to the direct children of the DOM node.
+        /// </param>
+        /// <returns>The node's first descendant DOM element that matches the specified namespace URI and local name; null otherwise.</returns>
+
+        var firstElement = null;
+        xmlTraverse(domNode, recursive, function (child) {
+            if (child.nodeType === 1) {
+                var isExpectedNamespace = !namespaceURI || xmlNamespaceURI(child) === namespaceURI;
+                var isExpectedNodeName = !localName || xmlLocalName(child) === localName;
+
+                if (isExpectedNamespace && isExpectedNodeName) {
+                    firstElement = child;
+                }
+            }
+            return firstElement === null;
+        });
+        return firstElement;
+    };
+
+    var xmlInnerText = function (xmlElement) {
+        /// <summary>Gets the concatenated value of all immediate child text and CDATA nodes for the specified element.</summary>
+        /// <param name="domElement">Element to get values for.</param>
+        /// <returns type="String">Text for all direct children.</returns>
+
+        var result = null;
+        var root = (xmlElement.nodeType === 9 && xmlElement.documentElement) ? xmlElement.documentElement : xmlElement;
+        var whitespaceAlreadyRemoved = root.ownerDocument.preserveWhiteSpace === false;
+        var whitespacePreserveContext;
+
+        xmlTraverse(root, false, function (child) {
+            if (child.nodeType === 3 || child.nodeType === 4) {
+                // isElementContentWhitespace indicates that this is 'ignorable whitespace',
+                // but it's not defined by all browsers, and does not honor xml:space='preserve'
+                // in some implementations.
+                //
+                // If we can't tell either way, we walk up the tree to figure out whether
+                // xml:space is set to preserve; otherwise we discard pure-whitespace.
+                //
+                // For example <a>  <b>1</b></a>. The space between <a> and <b> is usually 'ignorable'.
+                var text = xmlNodeValue(child);
+                var shouldInclude = whitespaceAlreadyRemoved || !isWhitespace(text);
+                if (!shouldInclude) {
+                    // Walk up the tree to figure out whether we are in xml:space='preserve' context
+                    // for the cursor (needs to happen only once).
+                    if (whitespacePreserveContext === undefined) {
+                        whitespacePreserveContext = isWhitespacePreserveContext(root);
+                    }
+
+                    shouldInclude = whitespacePreserveContext;
+                }
+
+                if (shouldInclude) {
+                    if (!result) {
+                        result = text;
+                    } else {
+                        result += text;
+                    }
+                }
+            }
+            // Continue traversing?
+            return true;
+        });
+        return result;
+    };
+
+    var xmlLocalName = function (domNode) {
+        /// <summary>Returns the localName of a XML node.</summary>
+        /// <param name="domNode">DOM node to get the value from.</param>
+        /// <returns type="String">localName of domNode.</returns>
+
+        return domNode.localName || domNode.baseName;
+    };
+
+    var xmlNamespaceURI = function (domNode) {
+        /// <summary>Returns the namespace URI of a XML node.</summary>
+        /// <param name="node">DOM node to get the value from.</param>
+        /// <returns type="String">Namespace URI of domNode.</returns>
+
+        return domNode.namespaceURI || null;
+    };
+
+    var xmlNodeValue = function (domNode) {
+        /// <summary>Returns the value or the inner text of a XML node.</summary>
+        /// <param name="node">DOM node to get the value from.</param>
+        /// <returns>Value of the domNode or the inner text if domNode represents a DOM element node.</returns>
+        
+        if (domNode.nodeType === 1) {
+            return xmlInnerText(domNode);
+        }
+        return domNode.nodeValue;
+    };
+
+    var xmlTraverse = function (domNode, recursive, onChildCallback) {
+        /// <summary>Walks through the descendants of the domNode and invokes a callback for each node.</summary>
+        /// <param name="domNode">DOM node whose descendants are going to be traversed.</param>
+        /// <param name="recursive" type="Boolean">
+        ///    True if the traversal should include all the descenants of the DOM node.
+        ///    False if the traversal should be scoped only to the direct children of the DOM node.
+        /// </param>
+        /// <returns type="String">Namespace URI of node.</returns>
+
+        var subtrees = [];
+        var child = domNode.firstChild;
+        var proceed = true;
+        while (child && proceed) {
+            proceed = onChildCallback(child);
+            if (proceed) {
+                if (recursive && child.firstChild) {
+                    subtrees.push(child.firstChild);
+                }
+                child = child.nextSibling || subtrees.shift();
+            }
+        }
+    };
+
+    var xmlSiblingElement = function (domNode, namespaceURI, localName) {
+        /// <summary>Returns the next sibling DOM element of the specified DOM node.</summary>
+        /// <param name="domNode">DOM node from which the next sibling is going to be retrieved.</param>
+        /// <param name="namespaceURI" type="String" optional="true">The namespace URI of the element to match.</param>
+        /// <param name="localName" type="String" optional="true">Name of the element to match.</param>
+        /// <returns>The node's next sibling DOM element, null if there is none.</returns>
+
+        var sibling = domNode.nextSibling;
+        while (sibling) {
+            if (sibling.nodeType === 1) {
+                var isExpectedNamespace = !namespaceURI || xmlNamespaceURI(sibling) === namespaceURI;
+                var isExpectedNodeName = !localName || xmlLocalName(sibling) === localName;
+
+                if (isExpectedNamespace && isExpectedNodeName) {
+                    return sibling;
+                }
+            }
+            sibling = sibling.nextSibling;
+        }
+        return null;
+    };
+
+    var xmlDom = function () {
+        /// <summary>Creates a new empty DOM document node.</summary>
+        /// <returns>New DOM document node.</returns>
+        /// <remarks>
+        ///    This function will first try to create a native DOM document using
+        ///    the browsers createDocument function.  If the browser doesn't
+        ///    support this but supports ActiveXObject, then an attempt to create
+        ///    an MSXML 6.0 DOM will be made. If this attempt fails too, then an attempt
+        ///    for creating an MXSML 3.0 DOM will be made.  If this last attemp fails or
+        ///    the browser doesn't support ActiveXObject then an exception will be thrown.
+        /// </remarks>
+
+        var implementation = window.document.implementation;
+        return (implementation && implementation.createDocument) ?
+           implementation.createDocument(null, null, null) :
+           msXmlDom();
+    };
+
+    var xmlAppendChildren = function (parent, children) {
+        /// <summary>Appends a collection of child nodes or string values to a parent DOM node.</summary>
+        /// <param name="parent">DOM node to which the children will be appended.</param>
+        /// <param name="children" type="Array">Array containing DOM nodes or string values that will be appended to the parent.</param>
+        /// <returns>The parent with the appended children or string values.</returns>
+        /// <remarks>
+        ///    If a value in the children collection is a string, then a new DOM text node is going to be created
+        ///    for it and then appended to the parent.
+        /// </remarks>
+
+        if (!isArray(children)) {
+            return xmlAppendChild(parent, children);
+        }
+
+        var i, len;
+        for (i = 0, len = children.length; i < len; i++) {
+            children[i] && xmlAppendChild(parent, children[i]);
+        }
+        return parent;
+    };
+
+    var xmlAppendChild = function (parent, child) {
+        /// <summary>Appends a child node or a string value to a parent DOM node.</summary>
+        /// <param name="parent">DOM node to which the child will be appended.</param>
+        /// <param name="child">Child DOM node or string value to append to the parent.</param>
+        /// <returns>The parent with the appended child or string value.</returns>
+        /// <remarks>
+        ///    If child is a string value, then a new DOM text node is going to be created
+        ///    for it and then appended to the parent.
+        /// </remarks>
+
+        djsassert(parent !== child, "xmlAppendChild() - parent and child are one and the same!");
+        if (child) {
+            if (typeof child === "string") {
+                return xmlAppendText(parent, xmlNewText(parent.ownerDocument, child));
+            }
+            if (child.nodeType === 2) {
+                parent.setAttributeNodeNS ? parent.setAttributeNodeNS(child) : parent.setAttributeNode(child);
+            } else {
+                parent.appendChild(child);
+            }
+        }
+        return parent;
+    };
+
+    var xmlNewAttribute = function (dom, namespaceURI, qualifiedName, value) {
+        /// <summary>Creates a new DOM attribute node.</summary>
+        /// <param name="dom">DOM document used to create the attribute.</param>
+        /// <param name="prefix" type="String">Namespace prefix.</param>
+        /// <param name="namespaceURI" type="String">Namespace URI.</param>
+        /// <returns>DOM attribute node for the namespace declaration.</returns>
+
+        var attribute =
+            dom.createAttributeNS && dom.createAttributeNS(namespaceURI, qualifiedName) ||
+            dom.createNode(2, qualifiedName, namespaceURI || undefined);
+
+        attribute.value = value || "";
+        return attribute;
+    };
+
+    var xmlNewElement = function (dom, nampespaceURI, qualifiedName, children) {
+        /// <summary>Creates a new DOM element node.</summary>
+        /// <param name="dom">DOM document used to create the DOM element.</param>
+        /// <param name="namespaceURI" type="String">Namespace URI of the new DOM element.</param>
+        /// <param name="qualifiedName" type="String">Qualified name in the form of "prefix:name" of the new DOM element.</param>
+        /// <param name="children" type="Array" optional="true">
+        ///     Collection of child DOM nodes or string values that are going to be appended to the new DOM element.
+        /// </param>
+        /// <returns>New DOM element.</returns>
+        /// <remarks>
+        ///    If a value in the children collection is a string, then a new DOM text node is going to be created
+        ///    for it and then appended to the new DOM element.
+        /// </remarks>
+
+        var element =
+            dom.createElementNS && dom.createElementNS(nampespaceURI, qualifiedName) ||
+            dom.createNode(1, qualifiedName, nampespaceURI || undefined);
+
+        return xmlAppendChildren(element, children || []);
+    };
+
+    var xmlNewNSDeclaration = function (dom, namespaceURI, prefix) {
+        /// <summary>Creates a namespace declaration attribute.</summary>
+        /// <param name="dom">DOM document used to create the attribute.</param>
+        /// <param name="namespaceURI" type="String">Namespace URI.</param>
+        /// <param name="prefix" type="String">Namespace prefix.</param>
+        /// <returns>DOM attribute node for the namespace declaration.</returns>
+
+        return xmlNewAttribute(dom, xmlnsNS, xmlQualifiedName("xmlns", prefix), namespaceURI);
+    };
+
+    var xmlNewFragment = function (dom, text) {
+        /// <summary>Creates a new DOM document fragment node for the specified xml text.</summary>
+        /// <param name="dom">DOM document from which the fragment node is going to be created.</param>
+        /// <param name="text" type="String" mayBeNull="false">XML text to be represented by the XmlFragment.</param>
+        /// <returns>New DOM document fragment object.</returns>
+
+        var value = "<c>" + text + "</c>";
+        var tempDom = xmlParse(value);
+        var tempRoot = tempDom.documentElement;
+        var imported = ("importNode" in dom) ? dom.importNode(tempRoot, true) : tempRoot;
+        var fragment = dom.createDocumentFragment();
+
+        var importedChild = imported.firstChild;
+        while (importedChild) {
+            fragment.appendChild(importedChild);
+            importedChild = importedChild.nextSibling;
+        }
+        return fragment;
+    };
+
+    var xmlNewText = function (dom, text) {
+        /// <summary>Creates new DOM text node.</summary>
+        /// <param name="dom">DOM document used to create the text node.</param>
+        /// <param name="text" type="String">Text value for the DOM text node.</param>
+        /// <returns>DOM text node.</returns>
+
+        return dom.createTextNode(text);
+    };
+
+    var xmlNewNodeByPath = function (dom, root, namespaceURI, prefix, path) {
+        /// <summary>Creates a new DOM element or DOM attribute node as specified by path and appends it to the DOM tree pointed by root.</summary>
+        /// <param name="dom">DOM document used to create the new node.</param>
+        /// <param name="root">DOM element node used as root of the subtree on which the new nodes are going to be created.</param>
+        /// <param name="namespaceURI" type="String">Namespace URI of the new DOM element or attribute.</param>
+        /// <param name="namespacePrefix" type="String">Prefix used to qualify the name of the new DOM element or attribute.</param>
+        /// <param name="Path" type="String">Path string describing the location of the new DOM element or attribute from the root element.</param>
+        /// <returns>DOM element or attribute node for the last segment of the path.</returns>
+        /// <remarks>
+        ///     This function will traverse the path and will create a new DOM element with the specified namespace URI and prefix
+        ///     for each segment that doesn't have a matching element under root.
+        ///
+        ///     The last segment of the path may be decorated with a starting @ character. In this case a new DOM attribute node
+        ///     will be created.
+        /// </remarks>
+
+        var name = "";
+        var parts = path.split("/");
+        var xmlFindNode = xmlFirstChildElement;
+        var xmlNewNode = xmlNewElement;
+        var xmlNode = root;
+
+        var i, len;
+        for (i = 0, len = parts.length; i < len; i++) {
+            name = parts[i];
+            if (name.charAt(0) === "@") {
+                name = name.substring(1);
+                xmlFindNode = xmlAttributeNode;
+                xmlNewNode = xmlNewAttribute;
+            }
+
+            var childNode = xmlFindNode(xmlNode, namespaceURI, name);
+            if (!childNode) {
+                childNode = xmlNewNode(dom, namespaceURI, xmlQualifiedName(prefix, name));
+                xmlAppendChild(xmlNode, childNode);
+            }
+            xmlNode = childNode;
+        }
+        return xmlNode;
+    };
+
+    var xmlSerialize = function (domNode) {
+        /// <summary>
+        /// Returns the text representation of the document to which the specified node belongs.
+        /// </summary>
+        /// <param name="root">Wrapped element in the document to serialize.</param>
+        /// <returns type="String">Serialized document.</returns>
+
+        var xmlSerializer = window.XMLSerializer;
+        if (xmlSerializer) {
+            var serializer = new xmlSerializer();
+            return serializer.serializeToString(domNode);
+        }
+
+        if (domNode.xml) {
+            return domNode.xml;
+        }
+
+        throw { message: "XML serialization unsupported" };
+    };
+
+    var xmlSerializeDescendants = function (domNode) {
+        /// <summary>Returns the XML representation of the all the descendants of the node.</summary>
+        /// <param name="domNode" optional="false" mayBeNull="false">Node to serialize.</param>
+        /// <returns type="String">The XML representation of all the descendants of the node.</returns>
+
+        var children = domNode.childNodes;
+        var i, len = children.length;
+        if (len === 0) {
+            return "";
+        }
+
+        // Some implementations of the XMLSerializer don't deal very well with fragments that
+        // don't have a DOMElement as their first child. The work around is to wrap all the
+        // nodes in a dummy root node named "c", serialize it and then just extract the text between
+        // the <c> and the </c> substrings.
+
+        var dom = domNode.ownerDocument;
+        var fragment = dom.createDocumentFragment();
+        var fragmentRoot = dom.createElement("c");
+
+        fragment.appendChild(fragmentRoot);
+        // Move the children to the fragment tree.
+        for (i = 0; i < len; i++) {
+            fragmentRoot.appendChild(children[i]);
+        }
+
+        var xml = xmlSerialize(fragment);
+        xml = xml.substr(3, xml.length - 7);
+
+        // Move the children back to the original dom tree.
+        for (i = 0; i < len; i++) {
+            domNode.appendChild(fragmentRoot.childNodes[i]);
+        }
+
+        return xml;
+    };
+
+    var xmlSerializeNode = function (domNode) {
+        /// <summary>Returns the XML representation of the node and all its descendants.</summary>
+        /// <param name="domNode" optional="false" mayBeNull="false">Node to serialize.</param>
+        /// <returns type="String">The XML representation of the node and all its descendants.</returns>
+
+        var xml = domNode.xml;
+        if (xml !== undefined) {
+            return xml;
+        }
+
+        if (window.XMLSerializer) {
+            var serializer = new window.XMLSerializer();
+            return serializer.serializeToString(domNode);
+        }
+
+        throw { message: "XML serialization unsupported" };
+    };
+
+    // DATAJS INTERNAL START
+
+    datajs.http = http;
+    datajs.w3org = w3org;
+    datajs.xmlNS = xmlNS;
+    datajs.xmlnsNS = xmlnsNS;
+
+    datajs.hasLeadingOrTrailingWhitespace = hasLeadingOrTrailingWhitespace;
+    datajs.isXmlNSDeclaration = isXmlNSDeclaration;
+    datajs.xmlAppendChild = xmlAppendChild;
+    datajs.xmlAppendChildren = xmlAppendChildren;
+    datajs.xmlAttributeNode = xmlAttributeNode;
+    datajs.xmlAttributes = xmlAttributes;
+    datajs.xmlAttributeValue = xmlAttributeValue;
+    datajs.xmlBaseURI = xmlBaseURI;
+    datajs.xmlChildElements = xmlChildElements;
+    datajs.xmlFindElementByPath = xmlFindElementByPath;
+    datajs.xmlFindNodeByPath = xmlFindNodeByPath;
+    datajs.xmlFirstChildElement = xmlFirstChildElement;
+    datajs.xmlFirstDescendantElement = xmlFirstDescendantElement;
+    datajs.xmlInnerText = xmlInnerText;
+    datajs.xmlLocalName = xmlLocalName;
+    datajs.xmlNamespaceURI = xmlNamespaceURI;
+    datajs.xmlNodeValue = xmlNodeValue;
+    datajs.xmlDom = xmlDom;
+    datajs.xmlNewAttribute = xmlNewAttribute;
+    datajs.xmlNewElement = xmlNewElement;
+    datajs.xmlNewFragment = xmlNewFragment;
+    datajs.xmlNewNodeByPath = xmlNewNodeByPath;
+    datajs.xmlNewNSDeclaration = xmlNewNSDeclaration;
+    datajs.xmlNewText = xmlNewText;
+    datajs.xmlParse = xmlParse;
+    datajs.xmlQualifiedName = xmlQualifiedName;
+    datajs.xmlSerialize = xmlSerialize;
+    datajs.xmlSerializeDescendants = xmlSerializeDescendants;
+    datajs.xmlSiblingElement = xmlSiblingElement;
+
+    // DATAJS INTERNAL END
+
+    // CONTENT END
+})(this);
\ No newline at end of file