Updated Asterix SDK + Easy XDM
diff --git a/asterix-app/src/main/resources/sdk/static/client.html b/asterix-app/src/main/resources/sdk/static/client.html
new file mode 100644
index 0000000..d421a7a1
--- /dev/null
+++ b/asterix-app/src/main/resources/sdk/static/client.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
+        <script src="js/easyXDM.debug.js" type="text/javascript"></script>
+        <script src="js/asterix-api-core.js" type="text/javascript"></script>
+        <script>
+            var a = new AsterixSDK();
+            a.requestHandler();
+        </script>
+    </head>
+    <body>
+        'ello
+    </body>
+</html>
diff --git a/asterix-app/src/main/resources/sdk/static/js/asterix-api-core.js b/asterix-app/src/main/resources/sdk/static/js/asterix-api-core.js
index 5821198..0d67c9b 100644
--- a/asterix-app/src/main/resources/sdk/static/js/asterix-api-core.js
+++ b/asterix-app/src/main/resources/sdk/static/js/asterix-api-core.js
@@ -1,14 +1,203 @@
+function AsterixSDK() {
+    
+    // Local RPC Handler for REST API
+    this.xhr = new easyXDM.Rpc({
+        remote: "http://localhost:19101/sdk/static/client.html"
+    }, {
+        remote: {
+            post: {}
+        }
+    });
+}
+
+
+AsterixSDK.prototype.send = function(handler) {
+    var api = handler.onSend();
+    this.xhr.post(
+        api.endpoint,
+        api.apiData,
+        function(data) {
+            alert("Sending Asterix SDK \n" + JSON.stringify(data));
+        }// handler.callback
+   );
+}
+
+
+AsterixSDK.prototype.client = function() {
+    this.xhr.post("http://www.localhost:19101/query",
+        {
+            "param" : "test"
+        },
+        function(data) {
+           // alert("hello world");
+        }
+    );
+}
+
+
+AsterixSDK.prototype.requestHandler = function() {
+    var rpc = new easyXDM.Rpc({}, {
+        local: {
+            post: {
+                method: function(url, data, fn, fnError){
+                    alert(url + "\ndata\n" + JSON.stringify(data));
+                }
+            }
+        }
+    });
+}
+
+
+// Asterix REST Controller
+// Handles interactions with remote database using a request handler
+function AsterixRESTController() {
+    
+    // REST DDL API
+    this.DDL = function(data, callback) {
+        this.endpoint = "http://localhost:19101/ddl";
+        this.apiData = data;
+        this.callback = callback;
+    };
+
+}
+
+AsterixRESTController.prototype.Update = function(json, data, callback) {
+    var endpoint = "http://localhost:19101/update";
+}
+
+
+AsterixRESTController.prototype.Query = function(json, data, callback) {
+    var endpoint = "http://localhost:19101/query";
+}
+
+
+AsterixRESTController.prototype.QueryStatus = function(json, data, callback) {
+    var endpoint = "http://localhost:19101/query/status";
+}
+
+
+AsterixRESTController.prototype.QueryResult = function(json, data, callback) {
+    var endpoint = "http://localhost:19101/query/result";
+}
+
+
+
+
+function AsterixSDKJQueryHandler(json, endpoint, callback) {
+    $.ajax({
+        type : 'GET',
+        url : endpoint,
+        data : json,
+        dataType : "json",
+        success : function(data) {
+            alert(JSON.stringify(data));
+        }
+    });
+}
+
+
+function AsterixExpression() {}
+
+
+// Create expressions
+// Create types, dataverses, indexes
+CreateExpression.prototype = new AsterixExpression();
+CreateExpression.prototype.constructor = CreateExpression;
+function CreateExpression(statement) {
+    this.value = statement;
+    this.send = this.onSend;
+}
+CreateExpression.prototype.onSend = function () {
+    var arc = new AsterixRESTController();
+    myThis = this;
+    arc.DDL( 
+        { "ddl" : myThis.value },
+        function () {}
+    );
+    return arc;
+};
+
+
+// For expressions
+// TODO Is this correct name?
+// TODO Probably query API
+ForExpression.prototype = new AsterixExpression();
+ForExpression.prototype.constructor = ForExpression;
+function ForExpression() {}
+ForExpression.prototype.onSend = function () {
+
+}
+
+// 
+
+/*
+// ************************
+// Asterix Query Manager
+// ************************
+
+// FOR REVIEW: This is not a good name, but I have no idea what to name it.
+function AsterixCoreJS() {
+    this.Expression = AQLExpression;
+    this.FLWOGR = AQLFLWOGR;
+    this.IfThenElse = AQLIfThenElse;
+}
+
+// ********************************
+// Asterix REST API Communication
+// ********************************
+function AsterixAPIRequest() {
+   var xmlhttp = new XMLHttpRequest();
+   xmlhttp.open("GET", "http://localhost:19101/query", true);
+   xmlhttp.setRequestHeader('Content-Type', 'application/json');
+   xmlhttp.send(JSON.stringify({"query" : "use dataverse dne;"}));
+   var serverResponse = xmlhttp.responseText;
+   alert(serverResponse);
+}
+
+// ********************
+// Asterix Expressions
+// ********************
+
 function AsterixExpression() {
 
+    // PRIVATE MEMBERS
+    
+    // PROTECTED METHODS
+    // * May be overridden with prototypes
+    // * May access private members
+    // * May not be changed
+   
+    // PUBLIC
 }
 
-function AsterixBindable() {
+// PUBLIC EXPRESSION PROPERTIES
+AsterixExpression.prototype.bindTo = function() {
 
 }
 
-function AsterixAPI() {
-    this.test = function() {
-        alert("testing");
-    };
-    return this;
+// For some AsterixExpression extension foo:
+// foo.prototype = new AsterixExpression();
+// foo.prototype.constructor = foo;
+// function foo() { // Set properties here }
+// foo.prototype.anotherMethod = function() { // Another example function }
+
+// AsterixFLWOGR
+// Inherits From: AsterixExpression
+//
+// FLWOGR   ::= ( ForClause | LetClause ) ( Clause )* "return" Expression
+AQLFLWOGR.prototype = new AsterixExpression();
+AQLFLWOGR.prototype.constructor = AQLFLWOGR;
+function AQLFLWOGR() {
+
 }
+
+// AsterixIfThenElse
+// Inherits From: AsterixExpression
+//
+// IfThenElse   ::= "if" <LEFTPAREN> Expression <RIGHTPAREN> "then" 
+// Expression "else" Expression
+AQLIfThenElse.prototype = new AsterixExpression();
+AQLIfThenElse.prototype.constructor = AQLIfThenElse;
+function AQLIfThenElse() {
+
+}*/
diff --git a/asterix-app/src/main/resources/sdk/static/js/easyXDM.debug.js b/asterix-app/src/main/resources/sdk/static/js/easyXDM.debug.js
new file mode 100644
index 0000000..61b9738
--- /dev/null
+++ b/asterix-app/src/main/resources/sdk/static/js/easyXDM.debug.js
@@ -0,0 +1,2871 @@
+/**
+ * easyXDM
+ * http://easyxdm.net/
+ * Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.
+ *
+ * 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.
+ */
+(function (window, document, location, setTimeout, decodeURIComponent, encodeURIComponent) {

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global JSON, XMLHttpRequest, window, escape, unescape, ActiveXObject */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// 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.

+//

+

+var global = this;

+var channelId = Math.floor(Math.random() * 10000); // randomize the initial id in case of multiple closures loaded 

+var emptyFn = Function.prototype;

+var reURI = /^((http.?:)\/\/([^:\/\s]+)(:\d+)*)/; // returns groups for protocol (2), domain (3) and port (4) 

+var reParent = /[\-\w]+\/\.\.\//; // matches a foo/../ expression 

+var reDoubleSlash = /([^:])\/\//g; // matches // anywhere but in the protocol

+var namespace = ""; // stores namespace under which easyXDM object is stored on the page (empty if object is global)

+var easyXDM = {};

+var _easyXDM = window.easyXDM; // map over global easyXDM in case of overwrite

+var IFRAME_PREFIX = "easyXDM_";

+var HAS_NAME_PROPERTY_BUG;

+var useHash = false; // whether to use the hash over the query

+var flashVersion; // will be set if using flash

+var HAS_FLASH_THROTTLED_BUG;

+var _trace = emptyFn;

+

+

+// http://peter.michaux.ca/articles/feature-detection-state-of-the-art-browser-scripting

+function isHostMethod(object, property){

+    var t = typeof object[property];

+    return t == 'function' ||

+    (!!(t == 'object' && object[property])) ||

+    t == 'unknown';

+}

+

+function isHostObject(object, property){

+    return !!(typeof(object[property]) == 'object' && object[property]);

+}

+

+// end

+

+// http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/

+function isArray(o){

+    return Object.prototype.toString.call(o) === '[object Array]';

+}

+

+// end

+function hasFlash(){

+    var name = "Shockwave Flash", mimeType = "application/x-shockwave-flash";

+    

+    if (!undef(navigator.plugins) && typeof navigator.plugins[name] == "object") {

+        // adapted from the swfobject code

+        var description = navigator.plugins[name].description;

+        if (description && !undef(navigator.mimeTypes) && navigator.mimeTypes[mimeType] && navigator.mimeTypes[mimeType].enabledPlugin) {

+            flashVersion = description.match(/\d+/g);

+        }

+    }

+    if (!flashVersion) {

+        var flash;

+        try {

+            flash = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");

+            flashVersion = Array.prototype.slice.call(flash.GetVariable("$version").match(/(\d+),(\d+),(\d+),(\d+)/), 1);

+            flash = null;

+        } 

+        catch (notSupportedException) {

+        }

+    }

+    if (!flashVersion) {

+        return false;

+    }

+    var major = parseInt(flashVersion[0], 10), minor = parseInt(flashVersion[1], 10);

+    HAS_FLASH_THROTTLED_BUG = major > 9 && minor > 0;

+    return true;

+}

+

+/*

+ * Cross Browser implementation for adding and removing event listeners.

+ */

+var on, un;

+if (isHostMethod(window, "addEventListener")) {

+    on = function(target, type, listener){

+        _trace("adding listener " + type);

+        target.addEventListener(type, listener, false);

+    };

+    un = function(target, type, listener){

+        _trace("removing listener " + type);

+        target.removeEventListener(type, listener, false);

+    };

+}

+else if (isHostMethod(window, "attachEvent")) {

+    on = function(object, sEvent, fpNotify){

+        _trace("adding listener " + sEvent);

+        object.attachEvent("on" + sEvent, fpNotify);

+    };

+    un = function(object, sEvent, fpNotify){

+        _trace("removing listener " + sEvent);

+        object.detachEvent("on" + sEvent, fpNotify);

+    };

+}

+else {

+    throw new Error("Browser not supported");

+}

+

+/*

+ * Cross Browser implementation of DOMContentLoaded.

+ */

+var domIsReady = false, domReadyQueue = [], readyState;

+if ("readyState" in document) {

+    // If browser is WebKit-powered, check for both 'loaded' (legacy browsers) and

+    // 'interactive' (HTML5 specs, recent WebKit builds) states.

+    // https://bugs.webkit.org/show_bug.cgi?id=45119

+    readyState = document.readyState;

+    domIsReady = readyState == "complete" || (~ navigator.userAgent.indexOf('AppleWebKit/') && (readyState == "loaded" || readyState == "interactive"));

+}

+else {

+    // If readyState is not supported in the browser, then in order to be able to fire whenReady functions apropriately

+    // when added dynamically _after_ DOM load, we have to deduce wether the DOM is ready or not.

+    // We only need a body to add elements to, so the existence of document.body is enough for us.

+    domIsReady = !!document.body;

+}

+

+function dom_onReady(){

+    if (domIsReady) {

+        return;

+    }

+    domIsReady = true;

+    _trace("firing dom_onReady");

+    for (var i = 0; i < domReadyQueue.length; i++) {

+        domReadyQueue[i]();

+    }

+    domReadyQueue.length = 0;

+}

+

+

+if (!domIsReady) {

+    if (isHostMethod(window, "addEventListener")) {

+        on(document, "DOMContentLoaded", dom_onReady);

+    }

+    else {

+        on(document, "readystatechange", function(){

+            if (document.readyState == "complete") {

+                dom_onReady();

+            }

+        });

+        if (document.documentElement.doScroll && window === top) {

+            var doScrollCheck = function(){

+                if (domIsReady) {

+                    return;

+                }

+                // http://javascript.nwbox.com/IEContentLoaded/

+                try {

+                    document.documentElement.doScroll("left");

+                } 

+                catch (e) {

+                    setTimeout(doScrollCheck, 1);

+                    return;

+                }

+                dom_onReady();

+            };

+            doScrollCheck();

+        }

+    }

+    

+    // A fallback to window.onload, that will always work

+    on(window, "load", dom_onReady);

+}

+/**

+ * This will add a function to the queue of functions to be run once the DOM reaches a ready state.

+ * If functions are added after this event then they will be executed immediately.

+ * @param {function} fn The function to add

+ * @param {Object} scope An optional scope for the function to be called with.

+ */

+function whenReady(fn, scope){

+    if (domIsReady) {

+        fn.call(scope);

+        return;

+    }

+    domReadyQueue.push(function(){

+        fn.call(scope);

+    });

+}

+

+/**

+ * Returns an instance of easyXDM from the parent window with

+ * respect to the namespace.

+ *

+ * @return An instance of easyXDM (in the parent window)

+ */

+function getParentObject(){

+    var obj = parent;

+    if (namespace !== "") {

+        for (var i = 0, ii = namespace.split("."); i < ii.length; i++) {

+            if (!obj) {

+                throw new Error(ii.slice(0, i + 1).join('.') + ' is not an object');

+            }

+            obj = obj[ii[i]];

+        }

+    }

+    if (!obj || !obj.easyXDM) {

+        throw new Error('Could not find easyXDM in parent.' + namespace);

+    }

+    return obj.easyXDM;

+}

+

+/**

+ * Removes easyXDM variable from the global scope. It also returns control

+ * of the easyXDM variable to whatever code used it before.

+ *

+ * @param {String} ns A string representation of an object that will hold

+ *                    an instance of easyXDM.

+ * @return An instance of easyXDM

+ */

+function noConflict(ns){

+    if (typeof ns != "string" || !ns) {

+        throw new Error('namespace must be a non-empty string');

+    }

+    _trace("Settings namespace to '" + ns + "'");

+    

+    window.easyXDM = _easyXDM;

+    namespace = ns;

+    if (namespace) {

+        IFRAME_PREFIX = "easyXDM_" + namespace.replace(".", "_") + "_";

+    }

+    return easyXDM;

+}

+

+/*

+ * Methods for working with URLs

+ */

+/**

+ * Get the domain name from a url.

+ * @param {String} url The url to extract the domain from.

+ * @return The domain part of the url.

+ * @type {String}

+ */

+function getDomainName(url){

+    if (!url) {

+        throw new Error("url is undefined or empty");

+    }

+    return url.match(reURI)[3];

+}

+

+/**

+ * Get the port for a given URL, or "" if none

+ * @param {String} url The url to extract the port from.

+ * @return The port part of the url.

+ * @type {String}

+ */

+function getPort(url){

+    if (!url) {

+        throw new Error("url is undefined or empty");

+    }

+    return url.match(reURI)[4] || "";

+}

+

+/**

+ * Returns  a string containing the schema, domain and if present the port

+ * @param {String} url The url to extract the location from

+ * @return {String} The location part of the url

+ */

+function getLocation(url){

+    if (!url) {

+        throw new Error("url is undefined or empty");

+    }

+    if (/^file/.test(url)) {

+        throw new Error("The file:// protocol is not supported");

+    }

+    var m = url.toLowerCase().match(reURI);

+    var proto = m[2], domain = m[3], port = m[4] || "";

+    if ((proto == "http:" && port == ":80") || (proto == "https:" && port == ":443")) {

+        port = "";

+    }

+    return proto + "//" + domain + port;

+}

+

+/**

+ * Resolves a relative url into an absolute one.

+ * @param {String} url The path to resolve.

+ * @return {String} The resolved url.

+ */

+function resolveUrl(url){

+    if (!url) {

+        throw new Error("url is undefined or empty");

+    }

+    

+    // replace all // except the one in proto with /

+    url = url.replace(reDoubleSlash, "$1/");

+    

+    // If the url is a valid url we do nothing

+    if (!url.match(/^(http||https):\/\//)) {

+        // If this is a relative path

+        var path = (url.substring(0, 1) === "/") ? "" : location.pathname;

+        if (path.substring(path.length - 1) !== "/") {

+            path = path.substring(0, path.lastIndexOf("/") + 1);

+        }

+        

+        url = location.protocol + "//" + location.host + path + url;

+    }

+    

+    // reduce all 'xyz/../' to just '' 

+    while (reParent.test(url)) {

+        url = url.replace(reParent, "");

+    }

+    

+    _trace("resolved url '" + url + "'");

+    return url;

+}

+

+/**

+ * Appends the parameters to the given url.<br/>

+ * The base url can contain existing query parameters.

+ * @param {String} url The base url.

+ * @param {Object} parameters The parameters to add.

+ * @return {String} A new valid url with the parameters appended.

+ */

+function appendQueryParameters(url, parameters){

+    if (!parameters) {

+        throw new Error("parameters is undefined or null");

+    }

+    

+    var hash = "", indexOf = url.indexOf("#");

+    if (indexOf !== -1) {

+        hash = url.substring(indexOf);

+        url = url.substring(0, indexOf);

+    }

+    var q = [];

+    for (var key in parameters) {

+        if (parameters.hasOwnProperty(key)) {

+            q.push(key + "=" + encodeURIComponent(parameters[key]));

+        }

+    }

+    return url + (useHash ? "#" : (url.indexOf("?") == -1 ? "?" : "&")) + q.join("&") + hash;

+}

+

+

+// build the query object either from location.query, if it contains the xdm_e argument, or from location.hash

+var query = (function(input){

+    input = input.substring(1).split("&");

+    var data = {}, pair, i = input.length;

+    while (i--) {

+        pair = input[i].split("=");

+        data[pair[0]] = decodeURIComponent(pair[1]);

+    }

+    return data;

+}(/xdm_e=/.test(location.search) ? location.search : location.hash));

+

+/*

+ * Helper methods

+ */

+/**

+ * Helper for checking if a variable/property is undefined

+ * @param {Object} v The variable to test

+ * @return {Boolean} True if the passed variable is undefined

+ */

+function undef(v){

+    return typeof v === "undefined";

+}

+

+/**

+ * A safe implementation of HTML5 JSON. Feature testing is used to make sure the implementation works.

+ * @return {JSON} A valid JSON conforming object, or null if not found.

+ */

+var getJSON = function(){

+    var cached = {};

+    var obj = {

+        a: [1, 2, 3]

+    }, json = "{\"a\":[1,2,3]}";

+    

+    if (typeof JSON != "undefined" && typeof JSON.stringify === "function" && JSON.stringify(obj).replace((/\s/g), "") === json) {

+        // this is a working JSON instance

+        return JSON;

+    }

+    if (Object.toJSON) {

+        if (Object.toJSON(obj).replace((/\s/g), "") === json) {

+            // this is a working stringify method

+            cached.stringify = Object.toJSON;

+        }

+    }

+    

+    if (typeof String.prototype.evalJSON === "function") {

+        obj = json.evalJSON();

+        if (obj.a && obj.a.length === 3 && obj.a[2] === 3) {

+            // this is a working parse method           

+            cached.parse = function(str){

+                return str.evalJSON();

+            };

+        }

+    }

+    

+    if (cached.stringify && cached.parse) {

+        // Only memoize the result if we have valid instance

+        getJSON = function(){

+            return cached;

+        };

+        return cached;

+    }

+    return null;

+};

+

+/**

+ * Applies properties from the source object to the target object.<br/>

+ * @param {Object} target The target of the properties.

+ * @param {Object} source The source of the properties.

+ * @param {Boolean} noOverwrite Set to True to only set non-existing properties.

+ */

+function apply(destination, source, noOverwrite){

+    var member;

+    for (var prop in source) {

+        if (source.hasOwnProperty(prop)) {

+            if (prop in destination) {

+                member = source[prop];

+                if (typeof member === "object") {

+                    apply(destination[prop], member, noOverwrite);

+                }

+                else if (!noOverwrite) {

+                    destination[prop] = source[prop];

+                }

+            }

+            else {

+                destination[prop] = source[prop];

+            }

+        }

+    }

+    return destination;

+}

+

+// This tests for the bug in IE where setting the [name] property using javascript causes the value to be redirected into [submitName].

+function testForNamePropertyBug(){

+    var form = document.body.appendChild(document.createElement("form")), input = form.appendChild(document.createElement("input"));

+    input.name = IFRAME_PREFIX + "TEST" + channelId; // append channelId in order to avoid caching issues

+    HAS_NAME_PROPERTY_BUG = input !== form.elements[input.name];

+    document.body.removeChild(form);

+    _trace("HAS_NAME_PROPERTY_BUG: " + HAS_NAME_PROPERTY_BUG);

+}

+

+/**

+ * Creates a frame and appends it to the DOM.

+ * @param config {object} This object can have the following properties

+ * <ul>

+ * <li> {object} prop The properties that should be set on the frame. This should include the 'src' property.</li>

+ * <li> {object} attr The attributes that should be set on the frame.</li>

+ * <li> {DOMElement} container Its parent element (Optional).</li>

+ * <li> {function} onLoad A method that should be called with the frames contentWindow as argument when the frame is fully loaded. (Optional)</li>

+ * </ul>

+ * @return The frames DOMElement

+ * @type DOMElement

+ */

+function createFrame(config){

+    _trace("creating frame: " + config.props.src);

+    if (undef(HAS_NAME_PROPERTY_BUG)) {

+        testForNamePropertyBug();

+    }

+    var frame;

+    // This is to work around the problems in IE6/7 with setting the name property. 

+    // Internally this is set as 'submitName' instead when using 'iframe.name = ...'

+    // This is not required by easyXDM itself, but is to facilitate other use cases 

+    if (HAS_NAME_PROPERTY_BUG) {

+        frame = document.createElement("<iframe name=\"" + config.props.name + "\"/>");

+    }

+    else {

+        frame = document.createElement("IFRAME");

+        frame.name = config.props.name;

+    }

+    

+    frame.id = frame.name = config.props.name;

+    delete config.props.name;

+    

+    if (typeof config.container == "string") {

+        config.container = document.getElementById(config.container);

+    }

+    

+    if (!config.container) {

+        // This needs to be hidden like this, simply setting display:none and the like will cause failures in some browsers.

+        apply(frame.style, {

+            position: "absolute",

+            top: "-2000px",

+            // Avoid potential horizontal scrollbar

+            left: "0px"

+        });

+        config.container = document.body;

+    }

+    

+    // HACK: IE cannot have the src attribute set when the frame is appended

+    //       into the container, so we set it to "javascript:false" as a

+    //       placeholder for now.  If we left the src undefined, it would

+    //       instead default to "about:blank", which causes SSL mixed-content

+    //       warnings in IE6 when on an SSL parent page.

+    var src = config.props.src;

+    config.props.src = "javascript:false";

+    

+    // transfer properties to the frame

+    apply(frame, config.props);

+    

+    frame.border = frame.frameBorder = 0;

+    frame.allowTransparency = true;

+    config.container.appendChild(frame);

+    

+    if (config.onLoad) {

+        on(frame, "load", config.onLoad);

+    }

+    

+    // set the frame URL to the proper value (we previously set it to

+    // "javascript:false" to work around the IE issue mentioned above)

+    if(config.usePost) {

+        var form = config.container.appendChild(document.createElement('form')), input;

+        form.target = frame.name;

+        form.action = src;

+        form.method = 'POST';

+        if (typeof(config.usePost) === 'object') {

+            for (var i in config.usePost) {

+                if (config.usePost.hasOwnProperty(i)) {

+                    if (HAS_NAME_PROPERTY_BUG) {

+                        input = document.createElement('<input name="' + i + '"/>');

+                    } else {

+                        input = document.createElement("INPUT");

+                        input.name = i;

+                    }

+                    input.value = config.usePost[i];

+                    form.appendChild(input);

+                }

+            }

+        }

+        form.submit();

+        form.parentNode.removeChild(form);

+    } else {

+        frame.src = src;

+    }

+    config.props.src = src;

+    

+    return frame;

+}

+

+/**

+ * Check whether a domain is allowed using an Access Control List.

+ * The ACL can contain * and ? as wildcards, or can be regular expressions.

+ * If regular expressions they need to begin with ^ and end with $.

+ * @param {Array/String} acl The list of allowed domains

+ * @param {String} domain The domain to test.

+ * @return {Boolean} True if the domain is allowed, false if not.

+ */

+function checkAcl(acl, domain){

+    // normalize into an array

+    if (typeof acl == "string") {

+        acl = [acl];

+    }

+    var re, i = acl.length;

+    while (i--) {

+        re = acl[i];

+        re = new RegExp(re.substr(0, 1) == "^" ? re : ("^" + re.replace(/(\*)/g, ".$1").replace(/\?/g, ".") + "$"));

+        if (re.test(domain)) {

+            return true;

+        }

+    }

+    return false;

+}

+

+/*

+ * Functions related to stacks

+ */

+/**

+ * Prepares an array of stack-elements suitable for the current configuration

+ * @param {Object} config The Transports configuration. See easyXDM.Socket for more.

+ * @return {Array} An array of stack-elements with the TransportElement at index 0.

+ */

+function prepareTransportStack(config){

+    var protocol = config.protocol, stackEls;

+    config.isHost = config.isHost || undef(query.xdm_p);

+    useHash = config.hash || false;

+    _trace("preparing transport stack");

+    

+    if (!config.props) {

+        config.props = {};

+    }

+    if (!config.isHost) {

+        _trace("using parameters from query");

+        config.channel = query.xdm_c.replace(/["'<>\\]/g, "");

+        config.secret = query.xdm_s;

+        config.remote = query.xdm_e.replace(/["'<>\\]/g, "");

+        ;

+        protocol = query.xdm_p;

+        if (config.acl && !checkAcl(config.acl, config.remote)) {

+            throw new Error("Access denied for " + config.remote);

+        }

+    }

+    else {

+        config.remote = resolveUrl(config.remote);

+        config.channel = config.channel || "default" + channelId++;

+        config.secret = Math.random().toString(16).substring(2);

+        if (undef(protocol)) {

+            if (getLocation(location.href) == getLocation(config.remote)) {

+                /*

+                 * Both documents has the same origin, lets use direct access.

+                 */

+                protocol = "4";

+            }

+            else if (isHostMethod(window, "postMessage") || isHostMethod(document, "postMessage")) {

+                /*

+                 * This is supported in IE8+, Firefox 3+, Opera 9+, Chrome 2+ and Safari 4+

+                 */

+                protocol = "1";

+            }

+            else if (config.swf && isHostMethod(window, "ActiveXObject") && hasFlash()) {

+                /*

+                 * The Flash transport superseedes the NixTransport as the NixTransport has been blocked by MS

+                 */

+                protocol = "6";

+            }

+            else if (navigator.product === "Gecko" && "frameElement" in window && navigator.userAgent.indexOf('WebKit') == -1) {

+                /*

+                 * This is supported in Gecko (Firefox 1+)

+                 */

+                protocol = "5";

+            }

+            else if (config.remoteHelper) {

+                /*

+                 * This is supported in all browsers that retains the value of window.name when

+                 * navigating from one domain to another, and where parent.frames[foo] can be used

+                 * to get access to a frame from the same domain

+                 */

+                protocol = "2";

+            }

+            else {

+                /*

+                 * This is supported in all browsers where [window].location is writable for all

+                 * The resize event will be used if resize is supported and the iframe is not put

+                 * into a container, else polling will be used.

+                 */

+                protocol = "0";

+            }

+            _trace("selecting protocol: " + protocol);

+        }

+        else {

+            _trace("using protocol: " + protocol);

+        }

+    }

+    config.protocol = protocol; // for conditional branching

+    switch (protocol) {

+        case "0":// 0 = HashTransport

+            apply(config, {

+                interval: 100,

+                delay: 2000,

+                useResize: true,

+                useParent: false,

+                usePolling: false

+            }, true);

+            if (config.isHost) {

+                if (!config.local) {

+                    _trace("looking for image to use as local");

+                    // If no local is set then we need to find an image hosted on the current domain

+                    var domain = location.protocol + "//" + location.host, images = document.body.getElementsByTagName("img"), image;

+                    var i = images.length;

+                    while (i--) {

+                        image = images[i];

+                        if (image.src.substring(0, domain.length) === domain) {

+                            config.local = image.src;

+                            break;

+                        }

+                    }

+                    if (!config.local) {

+                        _trace("no image found, defaulting to using the window");

+                        // If no local was set, and we are unable to find a suitable file, then we resort to using the current window 

+                        config.local = window;

+                    }

+                }

+                

+                var parameters = {

+                    xdm_c: config.channel,

+                    xdm_p: 0

+                };

+                

+                if (config.local === window) {

+                    // We are using the current window to listen to

+                    config.usePolling = true;

+                    config.useParent = true;

+                    config.local = location.protocol + "//" + location.host + location.pathname + location.search;

+                    parameters.xdm_e = config.local;

+                    parameters.xdm_pa = 1; // use parent

+                }

+                else {

+                    parameters.xdm_e = resolveUrl(config.local);

+                }

+                

+                if (config.container) {

+                    config.useResize = false;

+                    parameters.xdm_po = 1; // use polling

+                }

+                config.remote = appendQueryParameters(config.remote, parameters);

+            }

+            else {

+                apply(config, {

+                    channel: query.xdm_c,

+                    remote: query.xdm_e,

+                    useParent: !undef(query.xdm_pa),

+                    usePolling: !undef(query.xdm_po),

+                    useResize: config.useParent ? false : config.useResize

+                });

+            }

+            stackEls = [new easyXDM.stack.HashTransport(config), new easyXDM.stack.ReliableBehavior({}), new easyXDM.stack.QueueBehavior({

+                encode: true,

+                maxLength: 4000 - config.remote.length

+            }), new easyXDM.stack.VerifyBehavior({

+                initiate: config.isHost

+            })];

+            break;

+        case "1":

+            stackEls = [new easyXDM.stack.PostMessageTransport(config)];

+            break;

+        case "2":

+            config.remoteHelper = resolveUrl(config.remoteHelper);

+            stackEls = [new easyXDM.stack.NameTransport(config), new easyXDM.stack.QueueBehavior(), new easyXDM.stack.VerifyBehavior({

+                initiate: config.isHost

+            })];

+            break;

+        case "3":

+            stackEls = [new easyXDM.stack.NixTransport(config)];

+            break;

+        case "4":

+            stackEls = [new easyXDM.stack.SameOriginTransport(config)];

+            break;

+        case "5":

+            stackEls = [new easyXDM.stack.FrameElementTransport(config)];

+            break;

+        case "6":

+            if (!flashVersion) {

+                hasFlash();

+            }

+            stackEls = [new easyXDM.stack.FlashTransport(config)];

+            break;

+    }

+    // this behavior is responsible for buffering outgoing messages, and for performing lazy initialization

+    stackEls.push(new easyXDM.stack.QueueBehavior({

+        lazy: config.lazy,

+        remove: true

+    }));

+    return stackEls;

+}

+

+/**

+ * Chains all the separate stack elements into a single usable stack.<br/>

+ * If an element is missing a necessary method then it will have a pass-through method applied.

+ * @param {Array} stackElements An array of stack elements to be linked.

+ * @return {easyXDM.stack.StackElement} The last element in the chain.

+ */

+function chainStack(stackElements){

+    var stackEl, defaults = {

+        incoming: function(message, origin){

+            this.up.incoming(message, origin);

+        },

+        outgoing: function(message, recipient){

+            this.down.outgoing(message, recipient);

+        },

+        callback: function(success){

+            this.up.callback(success);

+        },

+        init: function(){

+            this.down.init();

+        },

+        destroy: function(){

+            this.down.destroy();

+        }

+    };

+    for (var i = 0, len = stackElements.length; i < len; i++) {

+        stackEl = stackElements[i];

+        apply(stackEl, defaults, true);

+        if (i !== 0) {

+            stackEl.down = stackElements[i - 1];

+        }

+        if (i !== len - 1) {

+            stackEl.up = stackElements[i + 1];

+        }

+    }

+    return stackEl;

+}

+

+/**

+ * This will remove a stackelement from its stack while leaving the stack functional.

+ * @param {Object} element The elment to remove from the stack.

+ */

+function removeFromStack(element){

+    element.up.down = element.down;

+    element.down.up = element.up;

+    element.up = element.down = null;

+}

+

+/*

+ * Export the main object and any other methods applicable

+ */

+/** 

+ * @class easyXDM

+ * A javascript library providing cross-browser, cross-domain messaging/RPC.

+ * @version 2.4.17.1

+ * @singleton

+ */

+apply(easyXDM, {

+    /**

+     * The version of the library

+     * @type {string}

+     */

+    version: "2.4.17.1",

+    /**

+     * This is a map containing all the query parameters passed to the document.

+     * All the values has been decoded using decodeURIComponent.

+     * @type {object}

+     */

+    query: query,

+    /**

+     * @private

+     */

+    stack: {},

+    /**

+     * Applies properties from the source object to the target object.<br/>

+     * @param {object} target The target of the properties.

+     * @param {object} source The source of the properties.

+     * @param {boolean} noOverwrite Set to True to only set non-existing properties.

+     */

+    apply: apply,

+    

+    /**

+     * A safe implementation of HTML5 JSON. Feature testing is used to make sure the implementation works.

+     * @return {JSON} A valid JSON conforming object, or null if not found.

+     */

+    getJSONObject: getJSON,

+    /**

+     * This will add a function to the queue of functions to be run once the DOM reaches a ready state.

+     * If functions are added after this event then they will be executed immediately.

+     * @param {function} fn The function to add

+     * @param {object} scope An optional scope for the function to be called with.

+     */

+    whenReady: whenReady,

+    /**

+     * Removes easyXDM variable from the global scope. It also returns control

+     * of the easyXDM variable to whatever code used it before.

+     *

+     * @param {String} ns A string representation of an object that will hold

+     *                    an instance of easyXDM.

+     * @return An instance of easyXDM

+     */

+    noConflict: noConflict

+});

+

+// Expose helper functions so we can test them

+apply(easyXDM, {

+    checkAcl: checkAcl,

+    getDomainName: getDomainName,

+    getLocation: getLocation,

+    appendQueryParameters: appendQueryParameters

+});

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global console, _FirebugCommandLine,  easyXDM, window, escape, unescape, isHostObject, undef, _trace, domIsReady, emptyFn, namespace */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// 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.

+//

+

+var debug = {

+    _deferred: [],

+    flush: function(){

+        this.trace("... deferred messages ...");

+        for (var i = 0, len = this._deferred.length; i < len; i++) {

+            this.trace(this._deferred[i]);

+        }

+        this._deferred.length = 0;

+        this.trace("... end of deferred messages ...");

+    },

+    getTime: function(){

+        var d = new Date(), h = d.getHours() + "", m = d.getMinutes() + "", s = d.getSeconds() + "", ms = d.getMilliseconds() + "", zeros = "000";

+        if (h.length == 1) {

+            h = "0" + h;

+        }

+        if (m.length == 1) {

+            m = "0" + m;

+        }

+        if (s.length == 1) {

+            s = "0" + s;

+        }

+        ms = zeros.substring(ms.length) + ms;

+        return h + ":" + m + ":" + s + "." + ms;

+    },

+    /**

+     * Logs the message to console.log if available

+     * @param {String} msg The message to log

+     */

+    log: function(msg){

+        // Uses memoizing to cache the implementation

+        if (!isHostObject(window, "console") || undef(console.log)) {

+            /**

+             * Sets log to be an empty function since we have no output available

+             * @ignore

+             */

+            this.log = emptyFn;

+        }

+        else {

+            /**

+             * Sets log to be a wrapper around console.log

+             * @ignore

+             * @param {String} msg

+             */

+            this.log = function(msg){

+                console.log(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ": " + msg);

+            };

+        }

+        this.log(msg);

+    },

+    /**

+     * Will try to trace the given message either to a DOMElement with the id "log",

+     * or by using console.info.

+     * @param {String} msg The message to trace

+     */

+    trace: function(msg){

+        // Uses memoizing to cache the implementation

+        if (!domIsReady) {

+            if (this._deferred.length === 0) {

+                easyXDM.whenReady(debug.flush, debug);

+            }

+            this._deferred.push(msg);

+            this.log(msg);

+        }

+        else {

+            var el = document.getElementById("log");

+            // is there a log element present?

+            if (el) {

+                /**

+                 * Sets trace to be a function that outputs the messages to the DOMElement with id "log"

+                 * @ignore

+                 * @param {String} msg

+                 */

+                this.trace = function(msg){

+                    try {

+                        el.appendChild(document.createElement("div")).appendChild(document.createTextNode(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ":" + msg));

+                        el.scrollTop = el.scrollHeight;

+                    } 

+                    catch (e) {

+                        //In case we are unloading

+                    }

+                };

+            }

+            else if (isHostObject(window, "console") && !undef(console.info)) {

+                /**

+                 * Sets trace to be a wrapper around console.info

+                 * @ignore

+                 * @param {String} msg

+                 */

+                this.trace = function(msg){

+                    console.info(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ":" + msg);

+                };

+            }

+            else {

+                /**

+                 * Create log window

+                 * @ignore

+                 */

+                var domain = location.host, windowname = domain.replace(/[\-.:]/g, "") + "easyxdm_log", logWin;

+                try {

+                    logWin = window.open("", windowname, "width=800,height=200,status=0,navigation=0,scrollbars=1");

+                } 

+                catch (e) {

+                }

+                if (logWin) {

+                    var doc = logWin.document;

+                    el = doc.getElementById("log");

+                    if (!el) {

+                        doc.write("<html><head><title>easyXDM log " + domain + "</title></head>");

+                        doc.write("<body><div id=\"log\"></div></body></html>");

+                        doc.close();

+                        el = doc.getElementById("log");

+                    }

+                    this.trace = function(msg){

+                        try {

+                            el.appendChild(doc.createElement("div")).appendChild(doc.createTextNode(location.host + (namespace ? ":" + namespace : "") + " - " + this.getTime() + ":" + msg));

+                            el.scrollTop = el.scrollHeight;

+                        } 

+                        catch (e) {

+                            //In case we are unloading

+                        }

+                    };

+                    this.trace("---- new logger at " + location.href);

+                }

+                

+                if (!el) {

+                    // We are unable to use any logging

+                    this.trace = emptyFn;

+                }

+            }

+            this.trace(msg);

+        }

+    },

+    /**

+     * Creates a method usable for tracing.

+     * @param {String} name The name the messages should be marked with

+     * @return {Function} A function that accepts a single string as argument.

+     */

+    getTracer: function(name){

+        return function(msg){

+            debug.trace(name + ": " + msg);

+        };

+    }

+};

+debug.log("easyXDM present on '" + location.href);

+easyXDM.Debug = debug;

+_trace = debug.getTracer("{Private}");

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, isHostObject, isHostMethod, un, on, createFrame, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// 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.

+//

+

+/** 

+ * @class easyXDM.DomHelper

+ * Contains methods for dealing with the DOM

+ * @singleton

+ */

+easyXDM.DomHelper = {

+    /**

+     * Provides a consistent interface for adding eventhandlers

+     * @param {Object} target The target to add the event to

+     * @param {String} type The name of the event

+     * @param {Function} listener The listener

+     */

+    on: on,

+    /**

+     * Provides a consistent interface for removing eventhandlers

+     * @param {Object} target The target to remove the event from

+     * @param {String} type The name of the event

+     * @param {Function} listener The listener

+     */

+    un: un,

+    /**

+     * Checks for the presence of the JSON object.

+     * If it is not present it will use the supplied path to load the JSON2 library.

+     * This should be called in the documents head right after the easyXDM script tag.

+     * http://json.org/json2.js

+     * @param {String} path A valid path to json2.js

+     */

+    requiresJSON: function(path){

+        if (!isHostObject(window, "JSON")) {

+            debug.log("loading external JSON");

+            // we need to encode the < in order to avoid an illegal token error

+            // when the script is inlined in a document.

+            document.write('<' + 'script type="text/javascript" src="' + path + '"><' + '/script>');

+        }

+        else {

+            debug.log("native JSON found");

+        }

+    }

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// 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.

+//

+

+(function(){

+    // The map containing the stored functions

+    var _map = {};

+    

+    /**

+     * @class easyXDM.Fn

+     * This contains methods related to function handling, such as storing callbacks.

+     * @singleton

+     * @namespace easyXDM

+     */

+    easyXDM.Fn = {

+        /**

+         * Stores a function using the given name for reference

+         * @param {String} name The name that the function should be referred by

+         * @param {Function} fn The function to store

+         * @namespace easyXDM.fn

+         */

+        set: function(name, fn){

+            this._trace("storing function " + name);

+            _map[name] = fn;

+        },

+        /**

+         * Retrieves the function referred to by the given name

+         * @param {String} name The name of the function to retrieve

+         * @param {Boolean} del If the function should be deleted after retrieval

+         * @return {Function} The stored function

+         * @namespace easyXDM.fn

+         */

+        get: function(name, del){

+            this._trace("retrieving function " + name);

+            var fn = _map[name];

+            if (!fn) {

+                this._trace(name + " not found");

+            }

+            

+            if (del) {

+                delete _map[name];

+            }

+            return fn;

+        }

+    };

+    

+    easyXDM.Fn._trace = debug.getTracer("easyXDM.Fn");

+}());

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, chainStack, prepareTransportStack, getLocation, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// 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.

+//

+

+/**

+ * @class easyXDM.Socket

+ * This class creates a transport channel between two domains that is usable for sending and receiving string-based messages.<br/>

+ * The channel is reliable, supports queueing, and ensures that the message originates from the expected domain.<br/>

+ * Internally different stacks will be used depending on the browsers features and the available parameters.

+ * <h2>How to set up</h2>

+ * Setting up the provider:

+ * <pre><code>

+ * var socket = new easyXDM.Socket({

+ * &nbsp; local: "name.html",

+ * &nbsp; onReady: function(){

+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the socket

+ * &nbsp; &nbsp; socket.postMessage("foo-message");

+ * &nbsp; },

+ * &nbsp; onMessage: function(message, origin) {

+ * &nbsp;&nbsp; alert("received " + message + " from " + origin);

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * Setting up the consumer:

+ * <pre><code>

+ * var socket = new easyXDM.Socket({

+ * &nbsp; remote: "http:&#47;&#47;remotedomain/page.html",

+ * &nbsp; remoteHelper: "http:&#47;&#47;remotedomain/name.html",

+ * &nbsp; onReady: function(){

+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the socket

+ * &nbsp; &nbsp; socket.postMessage("foo-message");

+ * &nbsp; },

+ * &nbsp; onMessage: function(message, origin) {

+ * &nbsp;&nbsp; alert("received " + message + " from " + origin);

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * If you are unable to upload the <code>name.html</code> file to the consumers domain then remove the <code>remoteHelper</code> property

+ * and easyXDM will fall back to using the HashTransport instead of the NameTransport when not able to use any of the primary transports.

+ * @namespace easyXDM

+ * @constructor

+ * @cfg {String/Window} local The url to the local name.html document, a local static file, or a reference to the local window.

+ * @cfg {Boolean} lazy (Consumer only) Set this to true if you want easyXDM to defer creating the transport until really needed. 

+ * @cfg {String} remote (Consumer only) The url to the providers document.

+ * @cfg {String} remoteHelper (Consumer only) The url to the remote name.html file. This is to support NameTransport as a fallback. Optional.

+ * @cfg {Number} delay The number of milliseconds easyXDM should try to get a reference to the local window.  Optional, defaults to 2000.

+ * @cfg {Number} interval The interval used when polling for messages. Optional, defaults to 300.

+ * @cfg {String} channel (Consumer only) The name of the channel to use. Can be used to set consistent iframe names. Must be unique. Optional.

+ * @cfg {Function} onMessage The method that should handle incoming messages.<br/> This method should accept two arguments, the message as a string, and the origin as a string. Optional.

+ * @cfg {Function} onReady A method that should be called when the transport is ready. Optional.

+ * @cfg {DOMElement|String} container (Consumer only) The element, or the id of the element that the primary iframe should be inserted into. If not set then the iframe will be positioned off-screen. Optional.

+ * @cfg {Array/String} acl (Provider only) Here you can specify which '[protocol]://[domain]' patterns that should be allowed to act as the consumer towards this provider.<br/>

+ * This can contain the wildcards ? and *.  Examples are 'http://example.com', '*.foo.com' and '*dom?.com'. If you want to use reqular expressions then you pattern needs to start with ^ and end with $.

+ * If none of the patterns match an Error will be thrown.  

+ * @cfg {Object} props (Consumer only) Additional properties that should be applied to the iframe. This can also contain nested objects e.g: <code>{style:{width:"100px", height:"100px"}}</code>. 

+ * Properties such as 'name' and 'src' will be overrided. Optional.

+ */

+easyXDM.Socket = function(config){

+    var trace = debug.getTracer("easyXDM.Socket");

+    trace("constructor");

+    

+    // create the stack

+    var stack = chainStack(prepareTransportStack(config).concat([{

+        incoming: function(message, origin){

+            config.onMessage(message, origin);

+        },

+        callback: function(success){

+            if (config.onReady) {

+                config.onReady(success);

+            }

+        }

+    }])), recipient = getLocation(config.remote);

+    

+    // set the origin

+    this.origin = getLocation(config.remote);

+	

+    /**

+     * Initiates the destruction of the stack.

+     */

+    this.destroy = function(){

+        stack.destroy();

+    };

+    

+    /**

+     * Posts a message to the remote end of the channel

+     * @param {String} message The message to send

+     */

+    this.postMessage = function(message){

+        stack.outgoing(message, recipient);

+    };

+    

+    stack.init();

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef,, chainStack, prepareTransportStack, debug, getLocation */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// 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.

+//

+

+/** 

+ * @class easyXDM.Rpc

+ * Creates a proxy object that can be used to call methods implemented on the remote end of the channel, and also to provide the implementation

+ * of methods to be called from the remote end.<br/>

+ * The instantiated object will have methods matching those specified in <code>config.remote</code>.<br/>

+ * This requires the JSON object present in the document, either natively, using json.org's json2 or as a wrapper around library spesific methods.

+ * <h2>How to set up</h2>

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; &#47;&#47; this configuration is equal to that used by the Socket.

+ * &nbsp; remote: "http:&#47;&#47;remotedomain/...",

+ * &nbsp; onReady: function(){

+ * &nbsp; &nbsp; &#47;&#47; you need to wait for the onReady callback before using the proxy

+ * &nbsp; &nbsp; rpc.foo(...

+ * &nbsp; }

+ * },{

+ * &nbsp; local: {..},

+ * &nbsp; remote: {..}

+ * });

+ * </code></pre>

+ * 

+ * <h2>Exposing functions (procedures)</h2>

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; ...

+ * },{

+ * &nbsp; local: {

+ * &nbsp; &nbsp; nameOfMethod: {

+ * &nbsp; &nbsp; &nbsp; method: function(arg1, arg2, success, error){

+ * &nbsp; &nbsp; &nbsp; &nbsp; ...

+ * &nbsp; &nbsp; &nbsp; }

+ * &nbsp; &nbsp; },

+ * &nbsp; &nbsp; &#47;&#47; with shorthand notation 

+ * &nbsp; &nbsp; nameOfAnotherMethod:  function(arg1, arg2, success, error){

+ * &nbsp; &nbsp; }

+ * &nbsp; },

+ * &nbsp; remote: {...}

+ * });

+ * </code></pre>

+

+ * The function referenced by  [method] will receive the passed arguments followed by the callback functions <code>success</code> and <code>error</code>.<br/>

+ * To send a successfull result back you can use

+ *     <pre><code>

+ *     return foo;

+ *     </pre></code>

+ * or

+ *     <pre><code>

+ *     success(foo);

+ *     </pre></code>

+ *  To return an error you can use

+ *     <pre><code>

+ *     throw new Error("foo error");

+ *     </code></pre>

+ * or

+ *     <pre><code>

+ *     error("foo error");

+ *     </code></pre>

+ *

+ * <h2>Defining remotely exposed methods (procedures/notifications)</h2>

+ * The definition of the remote end is quite similar:

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; ...

+ * },{

+ * &nbsp; local: {...},

+ * &nbsp; remote: {

+ * &nbsp; &nbsp; nameOfMethod: {}

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * To call a remote method use

+ * <pre><code>

+ * rpc.nameOfMethod("arg1", "arg2", function(value) {

+ * &nbsp; alert("success: " + value);

+ * }, function(message) {

+ * &nbsp; alert("error: " + message + );

+ * });

+ * </code></pre>

+ * Both the <code>success</code> and <code>errror</code> callbacks are optional.<br/>

+ * When called with no callback a JSON-RPC 2.0 notification will be executed.

+ * Be aware that you will not be notified of any errors with this method.

+ * <br/>

+ * <h2>Specifying a custom serializer</h2>

+ * If you do not want to use the JSON2 library for non-native JSON support, but instead capabilities provided by some other library

+ * then you can specify a custom serializer using <code>serializer: foo</code>

+ * <pre><code>

+ * var rpc = new easyXDM.Rpc({

+ * &nbsp; ...

+ * },{

+ * &nbsp; local: {...},

+ * &nbsp; remote: {...},

+ * &nbsp; serializer : {

+ * &nbsp; &nbsp; parse: function(string){ ... },

+ * &nbsp; &nbsp; stringify: function(object) {...}

+ * &nbsp; }

+ * });

+ * </code></pre>

+ * If <code>serializer</code> is set then the class will not attempt to use the native implementation.

+ * @namespace easyXDM

+ * @constructor

+ * @param {Object} config The underlying transports configuration. See easyXDM.Socket for available parameters.

+ * @param {Object} jsonRpcConfig The description of the interface to implement.

+ */

+easyXDM.Rpc = function(config, jsonRpcConfig){

+    var trace = debug.getTracer("easyXDM.Rpc");

+    trace("constructor");

+    

+    // expand shorthand notation

+    if (jsonRpcConfig.local) {

+        for (var method in jsonRpcConfig.local) {

+            if (jsonRpcConfig.local.hasOwnProperty(method)) {

+                var member = jsonRpcConfig.local[method];

+                if (typeof member === "function") {

+                    jsonRpcConfig.local[method] = {

+                        method: member

+                    };

+                }

+            }

+        }

+    }

+	

+    // create the stack

+    var stack = chainStack(prepareTransportStack(config).concat([new easyXDM.stack.RpcBehavior(this, jsonRpcConfig), {

+        callback: function(success){

+            if (config.onReady) {

+                config.onReady(success);

+            }

+        }

+    }]));

+	

+    // set the origin 

+    this.origin = getLocation(config.remote);

+	

+    

+    /**

+     * Initiates the destruction of the stack.

+     */

+    this.destroy = function(){

+        stack.destroy();

+    };

+    

+    stack.init();

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, un, on, apply, whenReady, getParentObject, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// 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.

+//

+

+/**

+ * @class easyXDM.stack.SameOriginTransport

+ * SameOriginTransport is a transport class that can be used when both domains have the same origin.<br/>

+ * This can be useful for testing and for when the main application supports both internal and external sources.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote document to communicate with.

+ */

+easyXDM.stack.SameOriginTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.SameOriginTransport");

+    trace("constructor");

+    var pub, frame, send, targetOrigin;

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            send(message);

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            if (frame) {

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            targetOrigin = getLocation(config.remote);

+            

+            if (config.isHost) {

+                // set up the iframe

+                apply(config.props, {

+                    src: appendQueryParameters(config.remote, {

+                        xdm_e: location.protocol + "//" + location.host + location.pathname,

+                        xdm_c: config.channel,

+                        xdm_p: 4 // 4 = SameOriginTransport

+                    }),

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                frame = createFrame(config);

+                easyXDM.Fn.set(config.channel, function(sendFn){

+                    send = sendFn;

+                    setTimeout(function(){

+                        pub.up.callback(true);

+                    }, 0);

+                    return function(msg){

+                        pub.up.incoming(msg, targetOrigin);

+                    };

+                });

+            }

+            else {

+                send = getParentObject().Fn.get(config.channel, true)(function(msg){

+                    pub.up.incoming(msg, targetOrigin);

+                });

+                setTimeout(function(){

+                    pub.up.callback(true);

+                }, 0);

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global global, easyXDM, window, getLocation, appendQueryParameters, createFrame, debug, apply, whenReady, IFRAME_PREFIX, namespace, resolveUrl, getDomainName, HAS_FLASH_THROTTLED_BUG, getPort, query*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// 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.

+//

+

+/**

+ * @class easyXDM.stack.FlashTransport

+ * FlashTransport is a transport class that uses an SWF with LocalConnection to pass messages back and forth.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote domain to communicate with.

+ * @cfg {String} secret the pre-shared secret used to secure the communication.

+ * @cfg {String} swf The path to the swf file

+ * @cfg {Boolean} swfNoThrottle Set this to true if you want to take steps to avoid beeing throttled when hidden.

+ * @cfg {String || DOMElement} swfContainer Set this if you want to control where the swf is placed

+ */

+easyXDM.stack.FlashTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.FlashTransport");

+    trace("constructor");

+    if (!config.swf) {

+        throw new Error("Path to easyxdm.swf is missing");

+    }

+    var pub, // the public interface

+ frame, send, targetOrigin, swf, swfContainer;

+    

+    function onMessage(message, origin){

+        setTimeout(function(){

+            trace("received message");

+            pub.up.incoming(message, targetOrigin);

+        }, 0);

+    }

+    

+    /**

+     * This method adds the SWF to the DOM and prepares the initialization of the channel

+     */

+    function addSwf(domain){

+        trace("creating factory with SWF from " + domain);

+        // the differentiating query argument is needed in Flash9 to avoid a caching issue where LocalConnection would throw an error.

+        var url = config.swf + "?host=" + config.isHost;

+        var id = "easyXDM_swf_" + Math.floor(Math.random() * 10000);

+        

+        // prepare the init function that will fire once the swf is ready

+        easyXDM.Fn.set("flash_loaded" + domain.replace(/[\-.]/g, "_"), function(){

+            easyXDM.stack.FlashTransport[domain].swf = swf = swfContainer.firstChild;

+            var queue = easyXDM.stack.FlashTransport[domain].queue;

+            for (var i = 0; i < queue.length; i++) {

+                queue[i]();

+            }

+            queue.length = 0;

+        });

+        

+        if (config.swfContainer) {

+            swfContainer = (typeof config.swfContainer == "string") ? document.getElementById(config.swfContainer) : config.swfContainer;

+        }

+        else {

+            // create the container that will hold the swf

+            swfContainer = document.createElement('div');

+            

+            // http://bugs.adobe.com/jira/browse/FP-4796

+            // http://tech.groups.yahoo.com/group/flexcoders/message/162365

+            // https://groups.google.com/forum/#!topic/easyxdm/mJZJhWagoLc

+            apply(swfContainer.style, HAS_FLASH_THROTTLED_BUG && config.swfNoThrottle ? {

+                height: "20px",

+                width: "20px",

+                position: "fixed",

+                right: 0,

+                top: 0

+            } : {

+                height: "1px",

+                width: "1px",

+                position: "absolute",

+                overflow: "hidden",

+                right: 0,

+                top: 0

+            });

+            document.body.appendChild(swfContainer);

+        }

+        

+        // create the object/embed

+        var flashVars = "callback=flash_loaded" + domain.replace(/[\-.]/g, "_") + "&proto=" + global.location.protocol + "&domain=" + getDomainName(global.location.href) + "&port=" + getPort(global.location.href) + "&ns=" + namespace;

+        flashVars += "&log=true";

+        swfContainer.innerHTML = "<object height='20' width='20' type='application/x-shockwave-flash' id='" + id + "' data='" + url + "'>" +

+        "<param name='allowScriptAccess' value='always'></param>" +

+        "<param name='wmode' value='transparent'>" +

+        "<param name='movie' value='" +

+        url +

+        "'></param>" +

+        "<param name='flashvars' value='" +

+        flashVars +

+        "'></param>" +

+        "<embed type='application/x-shockwave-flash' FlashVars='" +

+        flashVars +

+        "' allowScriptAccess='always' wmode='transparent' src='" +

+        url +

+        "' height='1' width='1'></embed>" +

+        "</object>";

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            swf.postMessage(config.channel, message.toString());

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            try {

+                swf.destroyChannel(config.channel);

+            } 

+            catch (e) {

+            }

+            swf = null;

+            if (frame) {

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            

+            targetOrigin = config.remote;

+            

+            // Prepare the code that will be run after the swf has been intialized

+            easyXDM.Fn.set("flash_" + config.channel + "_init", function(){

+                setTimeout(function(){

+                    trace("firing onReady");

+                    pub.up.callback(true);

+                });

+            });

+            

+            // set up the omMessage handler

+            easyXDM.Fn.set("flash_" + config.channel + "_onMessage", onMessage);

+            

+            config.swf = resolveUrl(config.swf); // reports have been made of requests gone rogue when using relative paths

+            var swfdomain = getDomainName(config.swf);

+            var fn = function(){

+                // set init to true in case the fn was called was invoked from a separate instance

+                easyXDM.stack.FlashTransport[swfdomain].init = true;

+                swf = easyXDM.stack.FlashTransport[swfdomain].swf;

+                // create the channel

+                swf.createChannel(config.channel, config.secret, getLocation(config.remote), config.isHost);

+                

+                if (config.isHost) {

+                    // if Flash is going to be throttled and we want to avoid this

+                    if (HAS_FLASH_THROTTLED_BUG && config.swfNoThrottle) {

+                        apply(config.props, {

+                            position: "fixed",

+                            right: 0,

+                            top: 0,

+                            height: "20px",

+                            width: "20px"

+                        });

+                    }

+                    // set up the iframe

+                    apply(config.props, {

+                        src: appendQueryParameters(config.remote, {

+                            xdm_e: getLocation(location.href),

+                            xdm_c: config.channel,

+                            xdm_p: 6, // 6 = FlashTransport

+                            xdm_s: config.secret

+                        }),

+                        name: IFRAME_PREFIX + config.channel + "_provider"

+                    });

+                    frame = createFrame(config);

+                }

+            };

+            

+            if (easyXDM.stack.FlashTransport[swfdomain] && easyXDM.stack.FlashTransport[swfdomain].init) {

+                // if the swf is in place and we are the consumer

+                fn();

+            }

+            else {

+                // if the swf does not yet exist

+                if (!easyXDM.stack.FlashTransport[swfdomain]) {

+                    // add the queue to hold the init fn's

+                    easyXDM.stack.FlashTransport[swfdomain] = {

+                        queue: [fn]

+                    };

+                    addSwf(swfdomain);

+                }

+                else {

+                    easyXDM.stack.FlashTransport[swfdomain].queue.push(fn);

+                }

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, un, on, apply, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// 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.

+//

+

+/**

+ * @class easyXDM.stack.PostMessageTransport

+ * PostMessageTransport is a transport class that uses HTML5 postMessage for communication.<br/>

+ * <a href="http://msdn.microsoft.com/en-us/library/ms644944(VS.85).aspx">http://msdn.microsoft.com/en-us/library/ms644944(VS.85).aspx</a><br/>

+ * <a href="https://developer.mozilla.org/en/DOM/window.postMessage">https://developer.mozilla.org/en/DOM/window.postMessage</a>

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote domain to communicate with.

+ */

+easyXDM.stack.PostMessageTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.PostMessageTransport");

+    trace("constructor");

+    var pub, // the public interface

+ frame, // the remote frame, if any

+ callerWindow, // the window that we will call with

+ targetOrigin; // the domain to communicate with

+    /**

+     * Resolves the origin from the event object

+     * @private

+     * @param {Object} event The messageevent

+     * @return {String} The scheme, host and port of the origin

+     */

+    function _getOrigin(event){

+        if (event.origin) {

+            // This is the HTML5 property

+            return getLocation(event.origin);

+        }

+        if (event.uri) {

+            // From earlier implementations 

+            return getLocation(event.uri);

+        }

+        if (event.domain) {

+            // This is the last option and will fail if the 

+            // origin is not using the same schema as we are

+            return location.protocol + "//" + event.domain;

+        }

+        throw "Unable to retrieve the origin of the event";

+    }

+    

+    /**

+     * This is the main implementation for the onMessage event.<br/>

+     * It checks the validity of the origin and passes the message on if appropriate.

+     * @private

+     * @param {Object} event The messageevent

+     */

+    function _window_onMessage(event){

+        var origin = _getOrigin(event);

+        trace("received message '" + event.data + "' from " + origin);

+        if (origin == targetOrigin && event.data.substring(0, config.channel.length + 1) == config.channel + " ") {

+            pub.up.incoming(event.data.substring(config.channel.length + 1), origin);

+        }

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            callerWindow.postMessage(config.channel + " " + message, domain || targetOrigin);

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            un(window, "message", _window_onMessage);

+            if (frame) {

+                callerWindow = null;

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            targetOrigin = getLocation(config.remote);

+            if (config.isHost) {

+                // add the event handler for listening

+                var waitForReady = function(event){  

+                    if (event.data == config.channel + "-ready") {

+                        trace("firing onReady");

+                        // replace the eventlistener

+                        callerWindow = ("postMessage" in frame.contentWindow) ? frame.contentWindow : frame.contentWindow.document;

+                        un(window, "message", waitForReady);

+                        on(window, "message", _window_onMessage);

+                        setTimeout(function(){

+                            pub.up.callback(true);

+                        }, 0);

+                    }

+                };

+                on(window, "message", waitForReady);

+                

+                // set up the iframe

+                apply(config.props, {

+                    src: appendQueryParameters(config.remote, {

+                        xdm_e: getLocation(location.href),

+                        xdm_c: config.channel,

+                        xdm_p: 1 // 1 = PostMessage

+                    }),

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                frame = createFrame(config);

+            }

+            else {

+                // add the event handler for listening

+                on(window, "message", _window_onMessage);

+                callerWindow = ("postMessage" in window.parent) ? window.parent : window.parent.document;

+                callerWindow.postMessage(config.channel + "-ready", targetOrigin);

+                

+                setTimeout(function(){

+                    pub.up.callback(true);

+                }, 0);

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, appendQueryParameters, createFrame, debug, apply, query, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// 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.

+//

+

+/**

+ * @class easyXDM.stack.FrameElementTransport

+ * FrameElementTransport is a transport class that can be used with Gecko-browser as these allow passing variables using the frameElement property.<br/>

+ * Security is maintained as Gecho uses Lexical Authorization to determine under which scope a function is running.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remote The remote document to communicate with.

+ */

+easyXDM.stack.FrameElementTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.FrameElementTransport");

+    trace("constructor");

+    var pub, frame, send, targetOrigin;

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            send.call(this, message);

+            if (fn) {

+                fn();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            if (frame) {

+                frame.parentNode.removeChild(frame);

+                frame = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            targetOrigin = getLocation(config.remote);

+            

+            if (config.isHost) {

+                // set up the iframe

+                apply(config.props, {

+                    src: appendQueryParameters(config.remote, {

+                        xdm_e: getLocation(location.href),

+                        xdm_c: config.channel,

+                        xdm_p: 5 // 5 = FrameElementTransport

+                    }),

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                frame = createFrame(config);

+                frame.fn = function(sendFn){

+                    delete frame.fn;

+                    send = sendFn;

+                    setTimeout(function(){

+                        pub.up.callback(true);

+                    }, 0);

+                    // remove the function so that it cannot be used to overwrite the send function later on

+                    return function(msg){

+                        pub.up.incoming(msg, targetOrigin);

+                    };

+                };

+            }

+            else {

+                // This is to mitigate origin-spoofing

+                if (document.referrer && getLocation(document.referrer) != query.xdm_e) {

+                    window.top.location = query.xdm_e;

+                }

+                send = window.frameElement.fn(function(msg){

+                    pub.up.incoming(msg, targetOrigin);

+                });

+                pub.up.callback(true);

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef, getLocation, appendQueryParameters, resolveUrl, createFrame, debug, un, apply, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// 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.

+//

+

+/**

+ * @class easyXDM.stack.NameTransport

+ * NameTransport uses the window.name property to relay data.

+ * The <code>local</code> parameter needs to be set on both the consumer and provider,<br/>

+ * and the <code>remoteHelper</code> parameter needs to be set on the consumer.

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String} remoteHelper The url to the remote instance of hash.html - this is only needed for the host.

+ * @namespace easyXDM.stack

+ */

+easyXDM.stack.NameTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.NameTransport");

+    trace("constructor");

+    if (config.isHost && undef(config.remoteHelper)) {

+        trace("missing remoteHelper");

+        throw new Error("missing remoteHelper");

+    }

+    

+    var pub; // the public interface

+    var isHost, callerWindow, remoteWindow, readyCount, callback, remoteOrigin, remoteUrl;

+    

+    function _sendMessage(message){

+        var url = config.remoteHelper + (isHost ? "#_3" : "#_2") + config.channel;

+        trace("sending message " + message);

+        trace("navigating to  '" + url + "'");

+        callerWindow.contentWindow.sendMessage(message, url);

+    }

+    

+    function _onReady(){

+        if (isHost) {

+            if (++readyCount === 2 || !isHost) {

+                pub.up.callback(true);

+            }

+        }

+        else {

+            _sendMessage("ready");

+            trace("calling onReady");

+            pub.up.callback(true);

+        }

+    }

+    

+    function _onMessage(message){

+        trace("received message " + message);

+        pub.up.incoming(message, remoteOrigin);

+    }

+    

+    function _onLoad(){

+        if (callback) {

+            setTimeout(function(){

+                callback(true);

+            }, 0);

+        }

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain, fn){

+            callback = fn;

+            _sendMessage(message);

+        },

+        destroy: function(){

+            trace("destroy");

+            callerWindow.parentNode.removeChild(callerWindow);

+            callerWindow = null;

+            if (isHost) {

+                remoteWindow.parentNode.removeChild(remoteWindow);

+                remoteWindow = null;

+            }

+        },

+        onDOMReady: function(){

+            trace("init");

+            isHost = config.isHost;

+            readyCount = 0;

+            remoteOrigin = getLocation(config.remote);

+            config.local = resolveUrl(config.local);

+            

+            if (isHost) {

+                // Register the callback

+                easyXDM.Fn.set(config.channel, function(message){

+                    trace("received initial message " + message);

+                    if (isHost && message === "ready") {

+                        // Replace the handler

+                        easyXDM.Fn.set(config.channel, _onMessage);

+                        _onReady();

+                    }

+                });

+                

+                // Set up the frame that points to the remote instance

+                remoteUrl = appendQueryParameters(config.remote, {

+                    xdm_e: config.local,

+                    xdm_c: config.channel,

+                    xdm_p: 2

+                });

+                apply(config.props, {

+                    src: remoteUrl + '#' + config.channel,

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                remoteWindow = createFrame(config);

+            }

+            else {

+                config.remoteHelper = config.remote;

+                easyXDM.Fn.set(config.channel, _onMessage);

+            }

+            

+            // Set up the iframe that will be used for the transport

+            var onLoad = function(){

+                // Remove the handler

+                var w = callerWindow || this;

+                un(w, "load", onLoad);

+                easyXDM.Fn.set(config.channel + "_load", _onLoad);

+                (function test(){

+                    if (typeof w.contentWindow.sendMessage == "function") {

+                        _onReady();

+                    }

+                    else {

+                        setTimeout(test, 50);

+                    }

+                }());

+            };

+            

+            callerWindow = createFrame({

+                props: {

+                    src: config.local + "#_4" + config.channel

+                },

+                onLoad: onLoad

+            });

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, getLocation, createFrame, debug, un, on, apply, whenReady, IFRAME_PREFIX*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// 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.

+//

+

+/**

+ * @class easyXDM.stack.HashTransport

+ * HashTransport is a transport class that uses the IFrame URL Technique for communication.<br/>

+ * <a href="http://msdn.microsoft.com/en-us/library/bb735305.aspx">http://msdn.microsoft.com/en-us/library/bb735305.aspx</a><br/>

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The transports configuration.

+ * @cfg {String/Window} local The url to the local file used for proxying messages, or the local window.

+ * @cfg {Number} delay The number of milliseconds easyXDM should try to get a reference to the local window.

+ * @cfg {Number} interval The interval used when polling for messages.

+ */

+easyXDM.stack.HashTransport = function(config){

+    var trace = debug.getTracer("easyXDM.stack.HashTransport");

+    trace("constructor");

+    var pub;

+    var me = this, isHost, _timer, pollInterval, _lastMsg, _msgNr, _listenerWindow, _callerWindow;

+    var useParent, _remoteOrigin;

+    

+    function _sendMessage(message){

+        trace("sending message '" + (_msgNr + 1) + " " + message + "' to " + _remoteOrigin);

+        if (!_callerWindow) {

+            trace("no caller window");

+            return;

+        }

+        var url = config.remote + "#" + (_msgNr++) + "_" + message;

+        ((isHost || !useParent) ? _callerWindow.contentWindow : _callerWindow).location = url;

+    }

+    

+    function _handleHash(hash){

+        _lastMsg = hash;

+        trace("received message '" + _lastMsg + "' from " + _remoteOrigin);

+        pub.up.incoming(_lastMsg.substring(_lastMsg.indexOf("_") + 1), _remoteOrigin);

+    }

+    

+    /**

+     * Checks location.hash for a new message and relays this to the receiver.

+     * @private

+     */

+    function _pollHash(){

+        if (!_listenerWindow) {

+            return;

+        }

+        var href = _listenerWindow.location.href, hash = "", indexOf = href.indexOf("#");

+        if (indexOf != -1) {

+            hash = href.substring(indexOf);

+        }

+        if (hash && hash != _lastMsg) {

+            trace("poll: new message");

+            _handleHash(hash);

+        }

+    }

+    

+    function _attachListeners(){

+        trace("starting polling");

+        _timer = setInterval(_pollHash, pollInterval);

+    }

+    

+    return (pub = {

+        outgoing: function(message, domain){

+            _sendMessage(message);

+        },

+        destroy: function(){

+            window.clearInterval(_timer);

+            if (isHost || !useParent) {

+                _callerWindow.parentNode.removeChild(_callerWindow);

+            }

+            _callerWindow = null;

+        },

+        onDOMReady: function(){

+            isHost = config.isHost;

+            pollInterval = config.interval;

+            _lastMsg = "#" + config.channel;

+            _msgNr = 0;

+            useParent = config.useParent;

+            _remoteOrigin = getLocation(config.remote);

+            if (isHost) {

+                apply(config.props, {

+                    src: config.remote,

+                    name: IFRAME_PREFIX + config.channel + "_provider"

+                });

+                if (useParent) {

+                    config.onLoad = function(){

+                        _listenerWindow = window;

+                        _attachListeners();

+                        pub.up.callback(true);

+                    };

+                }

+                else {

+                    var tries = 0, max = config.delay / 50;

+                    (function getRef(){

+                        if (++tries > max) {

+                            trace("unable to get reference to _listenerWindow, giving up");

+                            throw new Error("Unable to reference listenerwindow");

+                        }

+                        try {

+                            _listenerWindow = _callerWindow.contentWindow.frames[IFRAME_PREFIX + config.channel + "_consumer"];

+                        } 

+                        catch (ex) {

+                        }

+                        if (_listenerWindow) {

+                            _attachListeners();

+                            trace("got a reference to _listenerWindow");

+                            pub.up.callback(true);

+                        }

+                        else {

+                            setTimeout(getRef, 50);

+                        }

+                    }());

+                }

+                _callerWindow = createFrame(config);

+            }

+            else {

+                _listenerWindow = window;

+                _attachListeners();

+                if (useParent) {

+                    _callerWindow = parent;

+                    pub.up.callback(true);

+                }

+                else {

+                    apply(config, {

+                        props: {

+                            src: config.remote + "#" + config.channel + new Date(),

+                            name: IFRAME_PREFIX + config.channel + "_consumer"

+                        },

+                        onLoad: function(){

+                            pub.up.callback(true);

+                        }

+                    });

+                    _callerWindow = createFrame(config);

+                }

+            }

+        },

+        init: function(){

+            whenReady(pub.onDOMReady, pub);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// 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.

+//

+

+/**

+ * @class easyXDM.stack.ReliableBehavior

+ * This is a behavior that tries to make the underlying transport reliable by using acknowledgements.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The behaviors configuration.

+ */

+easyXDM.stack.ReliableBehavior = function(config){

+    var trace = debug.getTracer("easyXDM.stack.ReliableBehavior");

+    trace("constructor");

+    var pub, // the public interface

+ callback; // the callback to execute when we have a confirmed success/failure

+    var idOut = 0, idIn = 0, currentMessage = "";

+    

+    return (pub = {

+        incoming: function(message, origin){

+            trace("incoming: " + message);

+            var indexOf = message.indexOf("_"), ack = message.substring(0, indexOf).split(",");

+            message = message.substring(indexOf + 1);

+            

+            if (ack[0] == idOut) {

+                trace("message delivered");

+                currentMessage = "";

+                if (callback) {

+                    callback(true);

+                    callback = null;

+                }

+            }

+            if (message.length > 0) {

+                trace("sending ack, and passing on " + message);

+                pub.down.outgoing(ack[1] + "," + idOut + "_" + currentMessage, origin);

+                if (idIn != ack[1]) {

+                    idIn = ack[1];

+                    pub.up.incoming(message, origin);

+                }

+            }

+            

+        },

+        outgoing: function(message, origin, fn){

+            currentMessage = message;

+            callback = fn;

+            pub.down.outgoing(idIn + "," + (++idOut) + "_" + message, origin);

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, debug, undef, removeFromStack*/

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// 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.

+//

+

+/**

+ * @class easyXDM.stack.QueueBehavior

+ * This is a behavior that enables queueing of messages. <br/>

+ * It will buffer incoming messages and dispach these as fast as the underlying transport allows.

+ * This will also fragment/defragment messages so that the outgoing message is never bigger than the

+ * set length.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The behaviors configuration. Optional.

+ * @cfg {Number} maxLength The maximum length of each outgoing message. Set this to enable fragmentation.

+ */

+easyXDM.stack.QueueBehavior = function(config){

+    var trace = debug.getTracer("easyXDM.stack.QueueBehavior");

+    trace("constructor");

+    var pub, queue = [], waiting = true, incoming = "", destroying, maxLength = 0, lazy = false, doFragment = false;

+    

+    function dispatch(){

+        if (config.remove && queue.length === 0) {

+            trace("removing myself from the stack");

+            removeFromStack(pub);

+            return;

+        }

+        if (waiting || queue.length === 0 || destroying) {

+            return;

+        }

+        trace("dispatching from queue");

+        waiting = true;

+        var message = queue.shift();

+        

+        pub.down.outgoing(message.data, message.origin, function(success){

+            waiting = false;

+            if (message.callback) {

+                setTimeout(function(){

+                    message.callback(success);

+                }, 0);

+            }

+            dispatch();

+        });

+    }

+    return (pub = {

+        init: function(){

+            if (undef(config)) {

+                config = {};

+            }

+            if (config.maxLength) {

+                maxLength = config.maxLength;

+                doFragment = true;

+            }

+            if (config.lazy) {

+                lazy = true;

+            }

+            else {

+                pub.down.init();

+            }

+        },

+        callback: function(success){

+            waiting = false;

+            var up = pub.up; // in case dispatch calls removeFromStack

+            dispatch();

+            up.callback(success);

+        },

+        incoming: function(message, origin){

+            if (doFragment) {

+                var indexOf = message.indexOf("_"), seq = parseInt(message.substring(0, indexOf), 10);

+                incoming += message.substring(indexOf + 1);

+                if (seq === 0) {

+                    trace("received the last fragment");

+                    if (config.encode) {

+                        incoming = decodeURIComponent(incoming);

+                    }

+                    pub.up.incoming(incoming, origin);

+                    incoming = "";

+                }

+                else {

+                    trace("waiting for more fragments, seq=" + message);

+                }

+            }

+            else {

+                pub.up.incoming(message, origin);

+            }

+        },

+        outgoing: function(message, origin, fn){

+            if (config.encode) {

+                message = encodeURIComponent(message);

+            }

+            var fragments = [], fragment;

+            if (doFragment) {

+                // fragment into chunks

+                while (message.length !== 0) {

+                    fragment = message.substring(0, maxLength);

+                    message = message.substring(fragment.length);

+                    fragments.push(fragment);

+                }

+                // enqueue the chunks

+                while ((fragment = fragments.shift())) {

+                    trace("enqueuing");

+                    queue.push({

+                        data: fragments.length + "_" + fragment,

+                        origin: origin,

+                        callback: fragments.length === 0 ? fn : null

+                    });

+                }

+            }

+            else {

+                queue.push({

+                    data: message,

+                    origin: origin,

+                    callback: fn

+                });

+            }

+            if (lazy) {

+                pub.down.init();

+            }

+            else {

+                dispatch();

+            }

+        },

+        destroy: function(){

+            trace("destroy");

+            destroying = true;

+            pub.down.destroy();

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef, debug */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// 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.

+//

+

+/**

+ * @class easyXDM.stack.VerifyBehavior

+ * This behavior will verify that communication with the remote end is possible, and will also sign all outgoing,

+ * and verify all incoming messages. This removes the risk of someone hijacking the iframe to send malicious messages.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} config The behaviors configuration.

+ * @cfg {Boolean} initiate If the verification should be initiated from this end.

+ */

+easyXDM.stack.VerifyBehavior = function(config){

+    var trace = debug.getTracer("easyXDM.stack.VerifyBehavior");

+    trace("constructor");

+    if (undef(config.initiate)) {

+        throw new Error("settings.initiate is not set");

+    }

+    var pub, mySecret, theirSecret, verified = false;

+    

+    function startVerification(){

+        trace("requesting verification");

+        mySecret = Math.random().toString(16).substring(2);

+        pub.down.outgoing(mySecret);

+    }

+    

+    return (pub = {

+        incoming: function(message, origin){

+            var indexOf = message.indexOf("_");

+            if (indexOf === -1) {

+                if (message === mySecret) {

+                    trace("verified, calling callback");

+                    pub.up.callback(true);

+                }

+                else if (!theirSecret) {

+                    trace("returning secret");

+                    theirSecret = message;

+                    if (!config.initiate) {

+                        startVerification();

+                    }

+                    pub.down.outgoing(message);

+                }

+            }

+            else {

+                if (message.substring(0, indexOf) === theirSecret) {

+                    pub.up.incoming(message.substring(indexOf + 1), origin);

+                }

+            }

+        },

+        outgoing: function(message, origin, fn){

+            pub.down.outgoing(mySecret + "_" + message, origin, fn);

+        },

+        callback: function(success){

+            if (config.initiate) {

+                startVerification();

+            }

+        }

+    });

+};

+/*jslint evil: true, browser: true, immed: true, passfail: true, undef: true, newcap: true*/

+/*global easyXDM, window, escape, unescape, undef, getJSON, debug, emptyFn, isArray */

+//

+// easyXDM

+// http://easyxdm.net/

+// Copyright(c) 2009-2011, Øyvind Sean Kinsey, oyvind@kinsey.no.

+//

+// 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.

+//

+

+/**

+ * @class easyXDM.stack.RpcBehavior

+ * This uses JSON-RPC 2.0 to expose local methods and to invoke remote methods and have responses returned over the the string based transport stack.<br/>

+ * Exposed methods can return values synchronous, asyncronous, or bet set up to not return anything.

+ * @namespace easyXDM.stack

+ * @constructor

+ * @param {Object} proxy The object to apply the methods to.

+ * @param {Object} config The definition of the local and remote interface to implement.

+ * @cfg {Object} local The local interface to expose.

+ * @cfg {Object} remote The remote methods to expose through the proxy.

+ * @cfg {Object} serializer The serializer to use for serializing and deserializing the JSON. Should be compatible with the HTML5 JSON object. Optional, will default to JSON.

+ */

+easyXDM.stack.RpcBehavior = function(proxy, config){

+    var trace = debug.getTracer("easyXDM.stack.RpcBehavior");

+    var pub, serializer = config.serializer || getJSON();

+    var _callbackCounter = 0, _callbacks = {};

+    

+    /**

+     * Serializes and sends the message

+     * @private

+     * @param {Object} data The JSON-RPC message to be sent. The jsonrpc property will be added.

+     */

+    function _send(data){

+        data.jsonrpc = "2.0";

+        pub.down.outgoing(serializer.stringify(data));

+    }

+    

+    /**

+     * Creates a method that implements the given definition

+     * @private

+     * @param {Object} The method configuration

+     * @param {String} method The name of the method

+     * @return {Function} A stub capable of proxying the requested method call

+     */

+    function _createMethod(definition, method){

+        var slice = Array.prototype.slice;

+        

+        trace("creating method " + method);

+        return function(){

+            trace("executing method " + method);

+            var l = arguments.length, callback, message = {

+                method: method

+            };

+            

+            if (l > 0 && typeof arguments[l - 1] === "function") {

+                //with callback, procedure

+                if (l > 1 && typeof arguments[l - 2] === "function") {

+                    // two callbacks, success and error

+                    callback = {

+                        success: arguments[l - 2],

+                        error: arguments[l - 1]

+                    };

+                    message.params = slice.call(arguments, 0, l - 2);

+                }

+                else {

+                    // single callback, success

+                    callback = {

+                        success: arguments[l - 1]

+                    };

+                    message.params = slice.call(arguments, 0, l - 1);

+                }

+                _callbacks["" + (++_callbackCounter)] = callback;

+                message.id = _callbackCounter;

+            }

+            else {

+                // no callbacks, a notification

+                message.params = slice.call(arguments, 0);

+            }

+            if (definition.namedParams && message.params.length === 1) {

+                message.params = message.params[0];

+            }

+            // Send the method request

+            _send(message);

+        };

+    }

+    

+    /**

+     * Executes the exposed method

+     * @private

+     * @param {String} method The name of the method

+     * @param {Number} id The callback id to use

+     * @param {Function} method The exposed implementation

+     * @param {Array} params The parameters supplied by the remote end

+     */

+    function _executeMethod(method, id, fn, params){

+        if (!fn) {

+            trace("requested to execute non-existent procedure " + method);

+            if (id) {

+                _send({

+                    id: id,

+                    error: {

+                        code: -32601,

+                        message: "Procedure not found."

+                    }

+                });

+            }

+            return;

+        }

+        

+        trace("requested to execute procedure " + method);

+        var success, error;

+        if (id) {

+            success = function(result){

+                success = emptyFn;

+                _send({

+                    id: id,

+                    result: result

+                });

+            };

+            error = function(message, data){

+                error = emptyFn;

+                var msg = {

+                    id: id,

+                    error: {

+                        code: -32099,

+                        message: message

+                    }

+                };

+                if (data) {

+                    msg.error.data = data;

+                }

+                _send(msg);

+            };

+        }

+        else {

+            success = error = emptyFn;

+        }

+        // Call local method

+        if (!isArray(params)) {

+            params = [params];

+        }

+        try {

+            var result = fn.method.apply(fn.scope, params.concat([success, error]));

+            if (!undef(result)) {

+                success(result);

+            }

+        } 

+        catch (ex1) {

+            error(ex1.message);

+        }

+    }

+    

+    return (pub = {

+        incoming: function(message, origin){

+            var data = serializer.parse(message);

+            if (data.method) {

+                trace("received request to execute method " + data.method + (data.id ? (" using callback id " + data.id) : ""));

+                // A method call from the remote end

+                if (config.handle) {

+                    config.handle(data, _send);

+                }

+                else {

+                    _executeMethod(data.method, data.id, config.local[data.method], data.params);

+                }

+            }

+            else {

+                trace("received return value destined to callback with id " + data.id);

+                // A method response from the other end

+                var callback = _callbacks[data.id];

+                if (data.error) {

+                    if (callback.error) {

+                        callback.error(data.error);

+                    }

+                    else {

+                        trace("unhandled error returned.");

+                    }

+                }

+                else if (callback.success) {

+                    callback.success(data.result);

+                }

+                delete _callbacks[data.id];

+            }

+        },

+        init: function(){

+            trace("init");

+            if (config.remote) {

+                trace("creating stubs");

+                // Implement the remote sides exposed methods

+                for (var method in config.remote) {

+                    if (config.remote.hasOwnProperty(method)) {

+                        proxy[method] = _createMethod(config.remote[method], method);

+                    }

+                }

+            }

+            pub.down.init();

+        },

+        destroy: function(){

+            trace("destroy");

+            for (var method in config.remote) {

+                if (config.remote.hasOwnProperty(method) && proxy.hasOwnProperty(method)) {

+                    delete proxy[method];

+                }

+            }

+            pub.down.destroy();

+        }

+    });

+};

+global.easyXDM = easyXDM;

+})(window, document, location, window.setTimeout, decodeURIComponent, encodeURIComponent);