// jOanda namespace with common utility methods
var jOanda = (function() {

    if (window.jOanda) {
        return jOanda;
    }

    var isReady = false;
    var readyBound = false;
    var readyList = [];

    var isLoaded = false;
    var loadedList = [];

    // Private functions
    function onWindowLoad(func) {
        var prev = window.onload;
        window.onload = function() {
            if (prev) {
                prev();
            }
            func();
        };
    }

    function bindLoaded() {
        if (window.addEventListener) {
            window.addEventListener("load", loaded, false);
        } else if (window.attachEvent) {
            window.attachEvent("onload", loaded);
        } else {
            onWindowLoad(loaded);
        }
    }

    // Based on jQuery source code from the trunk as of Sep 9, 2009
    function bindReady() {
        if (readyBound) {
            return;
        }
        readyBound = true;

        if (document.readyState === "complete") {
            ready();
            return;
        }
        // Mozilla, Opera and webkit nightlies currently support this event
        if (document.addEventListener) {
            // Use the handy event callback
            document.addEventListener("DOMContentLoaded", function() {
                document.removeEventListener("DOMContentLoaded", arguments.callee, false);
                ready();
            },
            false);

            // If IE event model is used
        } else if (document.attachEvent) {
            // ensure firing before onload,
            // maybe late but safe also for iframes
            document.attachEvent("onreadystatechange", function() {
                if (document.readyState === "complete") {
                    document.detachEvent("onreadystatechange", arguments.callee);
                    ready();
                }
            });

            // If IE and not an iframe
            // continually check to see if the document is ready
            if (document.documentElement.doScroll && window == window.top) { (function() {
                    if (isReady) {
                        return;
                    }

                    try {
                        // If IE is used, use the trick by Diego Perini
                        // http://javascript.nwbox.com/IEContentLoaded/
                        document.documentElement.doScroll("left");
                    } catch(error) {
                        setTimeout(arguments.callee, 0);
                        return;
                    }

                    // and execute any waiting functions
                    ready();
                })();
            }
        } else {
            // A fallback to window.onload, that will always work
            loadedList.push(func);
        }
    }

    function onready(func) {
        // Attach the listeners
        bindReady();

        if (isReady) {
            func.call(document);
        } else {
            readyList.push(func);
        }
    }

    function processCallbacks(list) {
        var fn, i = 0;
        while ((fn = list[i++])) {
            fn.call(document);
        }
    }

    function ready() {
        if (!isReady) {
            isReady = true;
            processCallbacks(readyList);
        }
    }

    function loaded() {
        if (!isLoaded) {
            isLoaded = true;
            processCallbacks(loadedList);
        }
    }

    function initialize() {
        var i;
        var orl = window.jOandaOnready || [];
        bindLoaded();
        for (i = 0; i < orl.length; i++) {
            onready(orl[i]);
        }
    }

    initialize();

    // Public API
    return {
        _id: 0,
        identity: function identity() {
                return this._id++;
        },
        // Attach a handler to window onload event
        onload: function(func) {
            if (isLoaded) {
                func.call(document);
            } else {
                loadedList.push(func);
            }
        },
        // Attach a handler to DOMContentLoaded event
        onready: function(func) {
            onready(func);
        },
        // Dynamically create/lookup a namespace to extend the jOanda object
        // e.g. jOanda.namespace('ui').tabs = object
        namespace: function(namespace) {
            var names = namespace.split('.'),
            ptr = this,
            name,
            i;

            for (i = 0; i < names.length; i++) {
                name = names[i];

                // create object if it does not exist
                if (ptr[name] === undefined) {
                    ptr[name] = {};
                }

                if (typeof(ptr[name]) !== 'object') {
                    throw "cannot install namespace " + namespace;
                }

                ptr = ptr[name];
            }
            return ptr;
        }
    };
})();
/*global jOanda */
jOanda.date = (function() {

    function pad(val, len) {
        val = String(val);
        len = len || 2;
        while (val.length < len) {
            val = "0" + val;
        }
        return val;
    }

    function local(timestamp) {
        var date = new Date(),
        months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
        timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[\-+]\d{4})?)\b/g,
        timezoneClip = /[^\-+\dA-Z]/g,
        date_builder;

        if(timestamp) {
            date.setTime(timestamp);
        }
        date_builder = [months[date.getMonth()], date.getDate() + ',', date.getFullYear(), pad(date.getHours()) + ':' + pad(date.getMinutes()), ((String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""))];

        return date_builder.join(' ');
    }

    return {
        local: local
    };
})();
/*global console, document, run_callbacks, include_scripts, jOanda, setTimeout, window */
var OANDAClientConfig = (function() {

    // the name of the js file called constitutes the name of the "callback"
    // in this case: OANDAClientConfig.load();
    var params;
    var callbacks   = [];

    // FLAGS

    // this will hold the events that we are running either
    // syncronously or asyncronously via jsonp
    var scripts     = [];

    // flag to show we've hit the run function
    var running = false;

    // flag to indicate we'eve retrieved the params
    var done = false;

    // flag that dictates whether we use the "onready" event
    // handling or by using the appendChild BEFORe on ready
    var force_synchronous = false;

    // flag to show the onready handler is already attached so we don't do it
    // more than once
    var onready_handler_attached = false;

    // METHODS

    function is_empty(obj) {
        for(var prop in obj) { if(obj.hasOwnProperty(prop)) { return false; } }
        return true;
    }

    //log
    function log(item) {
        if (
               typeof(console) !== 'undefined'
            && typeof(console.log) !== 'undefined'
            && false // delete this line to turn on debug log
        ) {
            console.log(item);
        }
        return;
    }

    // execute stored callbacks
    function run_callbacks() {
        if(!callbacks) { return; }
        var fn,i = 0;
        while ((fn = callbacks[i++])) {
            fn(params);
        }
        callbacks = null;
    }

    // this function is used for the JSONP callback
    // just dumps json into params and fires callbacks
    function load(json) {
        if ( done ) { return; }

        done    = true;
        params  = json;

        // we haven't got anything yet
        if ( typeof(params)  === "undefined" || is_empty(params) ) {
            log('no client config params');
            window.CT_X_cc_timer_fired = 1;
        }

        run_callbacks();
        return;
    }

    // helper func to write the script tag in synchronous mode
    function write_script(url) {
        if (typeof(url) === undefined || url.length < 1 ) { return; }
        document.write('<scr' + 'ipt src="'+url+'" type="text/javascript"></scr' + 'ipt>');
        return;
    }

    // this function changes mode to synchronous.
    // doesn't care if we're in a "running" state or not.
    // this allows "dumbness" such that something like blackberry
    // detection can occur before or after things have been initiated.
    function execute_before_domready() {
        if (force_synchronous) { return; }
        log('switching to synchronous mode');
        force_synchronous = true;

        // now we have to check to see if we're already running
        // in asyncrhonous mode
        if (running) {
            log('switching to synchronous mode when already running');
            include_scripts();
        }
    }

    // callback executed onready or when synchrnous mode is activated
    function include_scripts() {
        if( scripts.length === 0 ) { return; }

        // iterate over script includes
        var url, i=0;
        while ( (url = scripts[i++] ) ) {
            if(force_synchronous) {
                write_script(url);
            }
            else {
                var script_tag = document.createElement("script");
                script_tag.type = 'text/javascript';
                script_tag.src = url;
                document.body.appendChild(script_tag);
            }
        }
        scripts = [];
        onready_handler_attached = false;
        return;
    }

    // load the JSONP script using load as the callback
    function jsonp(url){

        // save the script's url
        scripts.push(url);

        // synchronous fallback
        if ( ! force_synchronous && typeof(jOanda) === "undefined" ) {
            log('jOanda is undefined so fallback to synchronous mode');
            force_synchronous = true;
        }

        // syncronous mode
        if (force_synchronous) {
            log('writing script tag ' + url);
            include_scripts();
        }
        // asyncronous mode
        else {
            log('appending child '+ url);

            // only attach the onready handler once
            if ( ! onready_handler_attached ) {
                onready_handler_attached = true;
                jOanda.onready(function() { include_scripts(); });
            }
        }
    }

    // includes the client config vars
    // timeout fallback in case of failure to load after 3 seconds
    function run() {
        if ( running ) { return; }
        running = true;
        
        var url = '/client_config/OANDAClientConfig.load.js'
                + '?src=/'
                + window.location.toString().split("/").slice(3).join('/');
        
        jsonp(url);
        setTimeout(function() { load({}); }, 10000);
        return;

    }

    return {
        // callbacks must accept one parameter which is
        // an object literal with the retunred config options
        'add_callback' : function(callback) {
            // add the callback
            if ( callbacks ) {
                callbacks.push(callback);
                if (!done) { run(); }
            }
            // run it if we already have it
            else  {
                callback(params);
            }
        },
        // can use this for external jsonp calls
        'load' : function(json) {
            load(json);
            return;
        },
        'get_params' : function() {
            return params;
        },
        'jsonp' : function(url) {
            jsonp(url);
            return;
        },
        'execute_before_domready': function() {
            execute_before_domready();
            return;
        }
    };
})();
/*global document, console, OANDAClientConfig, window, setTimeout */

var OANDAOPC = (function() {

    var cookie_name     = 'opc';
    var cookie_params;

    var done            = false;
    var running         = false;
    var callbacks       = [];


    function is_empty(obj) {
        for(var prop in obj) { if(obj.hasOwnProperty(prop)) { return false; } }
        return true;
    }

    //log
    function log(item) {
        if (
               typeof(console) !== 'undefined'
            && typeof(console.log) !== 'undefined'
            && false // remove this line (or change to true) for debugging
        ) {
            console.log(item);
        }
        return;
    }

    // iterate over and run callbacks
    function run_callbacks() {
        if(!callbacks) { return; }
        var fn,i = 0;
        while ((fn = callbacks[i++])) {
            fn();
        }
        callbacks = null;
    }

    // read a cookie
    function read_cookie(name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        for(var i=0;i < ca.length;i++) {
            var c = ca[i];
            while ( c.charAt(0) === ' ' ) {
                c = c.substring(1,c.length);
            }
            if (c.indexOf(nameEQ) === 0) {
                return c.substring(nameEQ.length,c.length);
            }
        }
        return null;
    }

    // set a cookie
    function create_cookie(name,value, epoch_seconds) {
        var expires     = "";
        var cookiestr   = "";
        if (epoch_seconds) {
            var date = new Date();
            date.setTime(epoch_seconds * 1000);
            expires = "; expires="+date.toGMTString();
        }
        cookiestr = name+"="+value+expires+"; path=/";
        document.cookie = cookiestr;
        return;
    }

    // this fires either via the callback from the OANDAClientConfig script
    // include or
    function load(json) {

        // race condition checks
        if (done) { return; }

        done = true;

        cookie_params = json;

        // we haven't got anything yet
        if (
               typeof(cookie_params)           === "undefined"
            || is_empty(cookie_params)
            || typeof(cookie_params.opc_token) === "undefined"
            || typeof(cookie_params.expires)   === "undefined"
        ) {
            log('no params');
            window.CT_X_xdc_timer_fired = 1;
            run_callbacks();
            return;
        }

        log('setting cookie');
        window.CT_X_xdc_opc_set = 1;
        create_cookie(
            cookie_name,
            cookie_params.opc_token,
            parseInt(cookie_params.expires, 10)
        );
        window.CT_X_xdc_dc = document.cookie;
        run_callbacks();
        return;


    }

    // callbacks HAVE to execute
    function run() {

        if (running) { return; }
        running = true;

        // check for existence of local cookie
        var token = read_cookie(cookie_name);
        var token_regex = /^(?:[A-F0-9]+-){4}(?:[A-F0-9]+)$/i;
        if (token) {
            if (token.length == 36 && token_regex.test(token)) {
                done = true;
                log('token found; do nothing');
                window.CT_X_xdc_opc_found = 1;
                run_callbacks();
                return;
            }
            log('bad token: ' + token + '(' + token.length + ')');
        }

        // test cookies
        if(!read_cookie('tc')) {
            create_cookie('tc','1');
            if(!read_cookie('tc')) {
                done = true;
                run_callbacks();
                log('cookies not on');
                window.CT_X_xdc_cookies_disabled = 1;
                return;
            }
        }

        // the oanda client config isn't loaded, so end
        // neither is the jOanda thingy for loading scripts
        if (typeof(OANDAClientConfig) === "undefined" ) {
            //alert('OANDAClientConfig not defined');
            done = true;
            log('OANDAClientConfig not found');
            run_callbacks();
            return;
        }

        OANDAClientConfig.add_callback(function(json) {
            // if we got nothing back from the cookie server, fire callbacks
            if (
                typeof(json) === 'undefined'
                || typeof(json.cookie_server) === 'undefined'
            ) {
                log('json empty');
                window.CT_X_xdc_cc_empty = 1;
                run_callbacks();
            }
            // do a jsonp callback to the cookie server now
            else {
                log('call to cookie server');
                OANDAClientConfig.jsonp(
                    window.location.protocol
                    + '//'
                    + json.cookie_server
                    + '/OANDAOPC.load.js'
                );
            }
            return;
        });
        // set a timeout callback to ensure that callbacks run
        setTimeout(function() { load({}); }, 10000);

        return;
    }

    // public interface
    return {
        'add_callback' : function(callback) {
            // add the callback
            if ( callbacks ) {
                callbacks.push(callback);
                if (!done) { run(); }
            }
            // run it if we already have it
            else  {
                callback.call();
            }
            return;
        },
        'run' : function() {
            if(!done) { run(); }
            return;
        },
        'load'  : function(json) {
            load(json);
            return;
        }
    };
})();
OANDAOPC.run();
/**
 *
 * bb_detect.js - This script is used to detect the Blackberry platform
 *
 */
var isBlackberryBrowser = (function() {
    if (navigator.platform === 'Blackberry') {
        return true;
    } else {
        return false;
    }
})();
/*global isBlackberryBrowser, OANDAClientConfig, clickTracksOANDA */
if (
       typeof(isBlackberryBrowser) !== "undefined"
    && typeof(OANDAClientConfig)   !== "undefined"
    && typeof(clickTracksOANDA)    !== "undefined"
    && isBlackberryBrowser
) {
    OANDAClientConfig.execute_before_domready();
    clickTracksOANDA.execute_before_domready();
}

var clickTracksSettings = (function() {
    var clickTracksDatasets = ['forexblog'];
    var serverPath = '//webstats.oanda.com/cgi-bin/ctasp-server.cgi?';
    var paths = [];
    var firstPartyJDC = 1;
    var firstPartyCookies = 1;
    var enableExitTracking = 0;
    var localLinks = [];
    var domainSuffixes = ['oanda.com', 'oanda.ae', 'oanda.sg', 'oanda.ca'];
    var otherFileExtensionsToReport = [];
    var firstPartyDomain = '';

    return {
        'clickTracksDatasets': function() {
            return clickTracksDatasets;
        },
        'serverPath': function() {
            return serverPath;
        },
        'paths': function() {
            return paths;
        },
        'firstPartyJDC': function() {
            return firstPartyJDC;
        },
        'firstPartyCookies': function() {
            return firstPartyCookies;
        },
        'enableExitTracking': function() {
            return enableExitTracking;
        },
        'localLinks': function() {
            return localLinks;
        },
        'domainSuffixes': function() {
            return domainSuffixes;
        },
        'otherFileExtensionsToReport': function() {
            return otherFileExtensionsToReport;
        },
        'firstPartyDomain': function() {
            return firstPartyDomain;
        }
    };
})();
/*global document,window, CT_I_Subdomain, Image, event, clickTracksSettings, OANDAClientConfig, OANDAOPC, jOanda */
var clickTracksOANDA = (function(defaultSettings) {

    // This variable ensures that our paramters are loaded before attempting to
    // log to click tracks
    var first_stage_done    = false;
    var CT_I_Datasets       = defaultSettings.clickTracksDatasets();
    var CT_I_Path           = defaultSettings.serverPath();
    // CT_I_... is an internally defined variable
    // window.CT_C_... is an internally named variable that the customer sets
    // window.CT_X_... is a customer defined variable to be written as a biscuit
    var paths = defaultSettings.paths();

    var CT_I_FirstPartyJDC      = defaultSettings.firstPartyJDC();
    var CT_I_FirstPartyCookies  = defaultSettings.firstPartyCookies();
    var CT_I_EnableExitTracking = defaultSettings.enableExitTracking();
    var CT_I_LocalLinks         = defaultSettings.localLinks();
    var CT_I_FirstPartyDomain   = defaultSettings.firstPartyDomain();
    var CT_I_OtherFileExtensionsToReport
        = defaultSettings.otherFileExtensionsToReport();
    var CT_I_DomainSuffixes     = [];

    // Variables to check if events have been fired
    var client_config_fired = false;
    var opc_fired = false;
    var onload_fired = false;
    var force_synchronous = false;

    if (defaultSettings.domainSuffixes) {
        CT_I_DomainSuffixes     = defaultSettings.domainSuffixes();
    }

    var callbacks   = [];

    // execute stored callbacks
    function run_callbacks() {
        if(!callbacks) { return; }
        var fn,i = 0;
        while ((fn = callbacks[i++])) {
            fn();
        }
        callbacks = null;
    }

    function load_script(url){
        var script = document.createElement("script");
        script.type = "text/javascript";
        if(callbacks) {
            if (script.readyState){  //IE
                script.onreadystatechange = function(){
                    if (script.readyState == "loaded" ||
                            script.readyState == "complete"){
                        script.onreadystatechange = null;
                        run_callbacks();
                    }
                };
            } else {  //Others
                script.onload = function(){
                    run_callbacks();
                };
            }
        }
        script.src = url;

        var elem =
        document.getElementsByTagName("head")[0].appendChild(script);
    }


    function load_params(json) {

        // this function is called to load the parameters from the site.cnf
        // file if the variables were set by client config, then we set them.
        // otherwise we ignore it.
        // all scalar values are strings
        if (typeof(json.clicktracks) !== 'undefined') {
            if (typeof(json.clicktracks.datasets) !== 'undefined') {
                if (typeof(json.clicktracks.datasets) === 'string') {
                    CT_I_Datasets = [json.clicktracks.datasets];
                } else {
                    CT_I_Datasets = json.clicktracks.datasets;
                }
            }
            if (typeof(json.clicktracks.serverPath) !== 'undefined') {
                CT_I_Path = json.clicktracks.serverPath;
            }
            if (typeof(json.clicktracks.paths) !== 'undefined') {
                paths = json.clicktracks.paths;
            }
            if (typeof(json.clicktracks.firstPartyJDC) !== 'undefined') {
                CT_I_FirstPartyJDC
                    = parseInt( json.clicktracks.firstPartyJDC, 10 );
            }
            if (typeof(json.clicktracks.firstPartyCookies) !== 'undefined') {
                CT_I_FirstPartyCookies
                    = parseInt( json.clicktracks.firstPartyCookies, 10 );
            }
            if (typeof(json.clicktracks.enableExitTracking) !== 'undefined') {
                CT_I_EnableExitTracking
                    = parseInt( json.clicktracks.enableExitTracking, 10 );
            }
            if (typeof(json.clicktracks.localLinks) !== 'undefined') {
                CT_I_LocalLinks = json.clicktracks.localLinks;
            }
            if (typeof(json.clicktracks.otherFileExtensionsToReport)
                 !== 'undefined') {
                CT_I_OtherFileExtensionsToReport
                    = json.clicktracks.otherFileExtensionsToReport;
            }
            if (typeof(json.clicktracks.firstPartyDomain) !== 'undefined') {
                CT_I_FirstPartyDomain = json.clicktracks.firstPartyDomain;
            }
            if (typeof(json.clicktracks.domainSuffixes) !== 'undefined') {
                if (typeof(json.clicktracks.domainSuffixes) === 'string') {
                    CT_I_DomainSuffixes = [json.clicktracks.domainSuffixes];
                } else {
                    CT_I_DomainSuffixes = json.clicktracks.domainSuffixes;
                }
            }
        }

        client_config_fired = true;
        clickTracksOANDA.check_and_run();

        // check to see if exit tracking is suppose to be enabled
        if (clickTracksOANDA.CT_I_EnableExitTracking()) {
            if (document.addEventListener) { // handle DOM 2 (Mozilla 6)
                document.addEventListener('click', 
                                          clickTracksOANDA.CT_ProcClick,
                                          false);
            } else {
                document.attachEvent('onclick', clickTracksOANDA.CT_ProcClick);
            }
        }

    }

    function cookies_set() {
        opc_fired = true;
        clickTracksOANDA.check_and_run();
    }

    function check_and_run() {
        if (client_config_fired && opc_fired && (force_synchronous || onload_fired)) {
            clickTracksOANDA.CT_RecordView();
        }
    }

    function record_view(request, method, additionalParams, server, skip_busy_loop, datasets ) {
        // set defaults
        var basicCall = true;
        if (request === null || request === undefined) {
            request = document.location;
        } else {
            basicCall = false;
        }
        additionalParams = additionalParams || []; //default
        server = server || CT_I_Path; //default

        if (typeof(window.CT_R_PID) != 'undefined') {
            request += (/\?/.test(request) ? '&' : '?')
                + 'CT_R_PID=' + encodeURIComponent(window.CT_R_PID);
        }
        var orderTotal = 0;
        //if (typeof(window.CT_C_OrderTotal) != 'undefined') {
        //    orderTotal = window.CT_C_OrderTotal;
        //}

        // handle biscuits first
        var biscuits = [];
        for (var i in window) {
            // if variable name starts with CT_X_ and by something else
            if (i.substring(0, 5) == 'CT_X_' && i.length > 5) {
				var s = window[i] + '';
				biscuits.push(encodeURIComponent(i + '=' + s));
            }
        }
        var ctxValue = biscuits.join('%26');

        // setup request fields
        var vals = additionalParams.concat(); //clone array into vals
        //Override default datasets
        if (datasets !== undefined) {
            vals.push('i=' + datasets.join('&amp;i='));
        }
        else {
            vals.push('i=' + CT_I_Datasets.join('&amp;i='));
        }
        vals.push('r=' + encodeURIComponent(request));
        if (CT_I_FirstPartyJDC) {
            if (window.CT_I_FirstPartyDomain
                && window.CT_I_FirstPartyDomain !== '') {
                vals.push('fp=' + window.CT_I_FirstPartyDomain);
            } else {
                vals.push('fp=1');
            }
        }
        if (CT_I_FirstPartyCookies || CT_I_FirstPartyJDC) {
            vals.push('c=' + encodeURIComponent(document.cookie));
        }
        if (method !== null && method !== undefined) {
            vals.push('s=' + method); // method

            // referrer
            vals.push('f=' + encodeURIComponent(document.location));
        } else {

            // referrer
            vals.push('f=' + encodeURIComponent(document.referrer));
            if (orderTotal > 0) {
                vals.push('e=' + orderTotal);
            }
        }
        if (typeof(CT_I_Subdomain) != 'undefined') {
            vals.push('d=' + encodeURIComponent(CT_I_Subdomain));
        }
        if (ctxValue !== '') {
            vals.push('U=' + ctxValue); // biscuits
        }
        if (!basicCall) {
            vals.push('g=1'); // use graphic as response
        }
        if (typeof(window.CT_I_Protocol) == 'undefined') {
            window.CT_I_Protocol = window.location.protocol;
        }

        // screen dimensions
        vals.push('sd=' + window.screen.width + 'x' + window.screen.height);

        var path = window.CT_I_Protocol + server + vals.join('&');

        /*var debug = window.CT_C_Debug;
        if (debug) {
            var debugMsg = 'ClickTracks JavaScript Data\n';
            if (orderTotal !== 0) {
                debugMsg += 'OrderTotal = ' + orderTotal.toFixed(2) + '\n';
            }
            if (biscuits.length > 0) {
                debugMsg += 'Biscuits:\n  ' + biscuits.join('\n  ') + '\n';
            }
            if (debug > 1) {
                debugMsg += 'Request:\n  ' + path + '\n';
            }
            if (basicCall) {
                debugMsg += '(Basic call)\n';
            } else {
                debugMsg += '(Advanced call)\n';
            }
            debugMsg += '\n\nIf you set any other data, it was not set correctly.\n';
            alert(debugMsg);
        }*/

        if (basicCall) {

            // called to log the page being loaded, JavaScript can still
            // be added to and executed
            load_script(path);

        } else {
            // called by exit tracking or customer activity
            var a = new Image();
            a.src = path;

            if ( ! skip_busy_loop ) {
                var now = new Date();
                now = now.getTime() + 1000;
                var then;
                do {
                    then = new Date();
                } while (then.getTime() < now);
            }
        }
    }

    return {
        'load_params': function(json) {
           load_params(json);
        },
        'cookies_set': function() {
            cookies_set();
        },
        'check_and_run': function() {
            check_and_run();
        },
        'execute_before_domready': function() {
            force_synchronous = true;
        },
        'onload': function() {
            onload_fired = true;
            clickTracksOANDA.check_and_run();
        },
        'add_callback' : function(callback) {
            // add the callback
            if ( callbacks ) { callbacks.push(callback); }
            // run it if we already have it
            else  { callback(); }
        },
        CT_I_EnableExitTracking: function() { return CT_I_EnableExitTracking; },

        //- additionalParams MAY be undefined. If set it MUST be either null
        //  or an array of additional parameters to pass, encoded
        //  as "key=value". e.g. additionalParams = [ "some_param=somevalue",
        //  "some_other_param=blah" ];
        //- server MAY be undefined. If set it MUST be either null or a
        //  non-empty string indicating where to send the message
        //  to. e.g. server ="jdc.ct.com". do not include protocol or trailing /s.
        //- datasets MAY be undefined.  If set it MUST be an array of dataset names
        //  to use instead of the ones in defaultSettings
        CT_RecordView: function(request, method, additionalParams, server, datasets ) {
            // 2nd last arg is "skip busy loop"
            record_view( request, method, additionalParams, server, false, datasets);
        }, // CT_RecordView()

        //- additionalParams MAY be undefined. If set it MUST be either null
        //  or an array of additional parameters to pass, encoded
        //  as "key=value". e.g. additionalParams = [ "some_param=somevalue",
        //  "some_other_param=blah" ];
        //- server MAY be undefined. If set it MUST be either null or a
        //  non-empty string indicating where to send the message
        //  to. e.g. server ="jdc.ct.com". do not include protocol or trailing /s.
        //- datasets MAY be undefined.  If set it MUST be an array of dataset names
        //  to use instead of the ones in defaultSettings
        CT_RecordViewSleepless: function(request, method, additionalParams, server, datasets ) {
            // 2nd last arg is "skip busy loop"
            record_view( request, method, additionalParams, server, true, datasets);
        }, // CT_RecordView()


        CT_ProcClick: function(evt) {
            evt = (evt) ? evt : ((window.event) ? event : null);
            if (evt) {
                var e = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
                while (e) {
                    var link = '';
                    switch(e.tagName) {
                    case 'A':
                    case 'AREA':
                        link = e.href;
                        break;
                    case 'INPUT':
                        if (e.form) {
                            e = e.form;
                            link = e.action;
                            if (link === '') {
                                link = document.location.href;
                            }
                        } else {
                            link = '';
                        }
                        break;
                    }
                    switch(e.tagName) {
                    case 'A':
                    case 'AREA':
                        if (link !== '') {
                            if (!clickTracksOANDA.CT_LocalLink(link)
                                && !clickTracksOANDA.CT_PartOfDomainSuffix(link)) {
                                clickTracksOANDA.CT_RecordView(link, 'EXIT');
                            } else if (clickTracksOANDA.CT_TrackFileExtension(link)) {
                                clickTracksOANDA.CT_RecordView(link, 'GET');
                            }
                        }
                        e = 0;
                        break;
                    default:
                        e = (e.parentElement) ? e.parentElement : e.parentNode;
                        break;
                    }
                }
            }
        }, // CT_ProcClick

        CT_TrackFileExtension: function(link) {
            link = link.split(/\?/)[0]; // get everything up to but not including ?
            link = link.toLowerCase();
            var l1 = link.length;
            for (var index = 0; index < CT_I_OtherFileExtensionsToReport.length; index++) {
                if (CT_I_OtherFileExtensionsToReport[index] !== ''
                    && link.substring(l1-CT_I_OtherFileExtensionsToReport[index].length-1)
                    == '.' + CT_I_OtherFileExtensionsToReport[index].toLowerCase()) {
                    return true;
                }
            }
            return false;
        },

        CT_LocalLink: function(link) {
            var pieces = link.match(/^https?:\/\/([^\/]+)\//);
            var localLinks = [];
            if (pieces) {
                if (CT_I_LocalLinks instanceof Array) {
                    localLinks = localLinks.concat(CT_I_LocalLinks);
                } else if (typeof(CT_I_LocalLinks) === "string") {
                    localLinks.push(CT_I_LocalLinks);
                }
                // also consider the current domain local
                localLinks.push(document.domain);
                for (var i in localLinks){
                    if (pieces[1] == localLinks[i]) {
                        return true;
                    }
                }
                return false;
            }
            return true;
        }, // CT_LocalLink

        CT_PartOfDomainSuffix: function(link) {
            var pieces = link.match(/^https?:\/\/([^\/]+)\//);
            if (pieces) {
                for (var i in CT_I_DomainSuffixes){
                    var domainSuffix = CT_I_DomainSuffixes[i];
                    var lastIndex = pieces[1].lastIndexOf(domainSuffix);

                    if (lastIndex !== -1
                        && pieces[1].substring(lastIndex) === domainSuffix) {
                        return true;
                    }
                }
                return false;
            }
            return true;
        } // CT_DomainSuffix
    };
})(clickTracksSettings);

document.write = function(s) {
    var v = /[<]script.+?src\s*=\s*"(\S+?)"/i.exec(s);
    if (v) {
      var e = document.createElement('script');
      e.type = 'text/javascript';
      e.src = v[1];
      document.getElementsByTagName("head")[0].appendChild(e);
    }
};
OANDAClientConfig.add_callback(clickTracksOANDA.load_params);
OANDAOPC.add_callback(clickTracksOANDA.cookies_set);
jOanda.onload(clickTracksOANDA.onload);
/*global jOanda, window */
jOanda.onload(function() {
    window.CT_X_onload_duration = new Date() - window.start_time;
});
jOanda.onready(function() {
    window.CT_X_onready_duration = new Date() - window.start_time;
});

