/**
 * SWFAddress 2.0: Deep linking for Flash and Ajax - http://www.asual.com/swfaddress/
 *
 * SWFAddress is (c) 2006-2007 Rostislav Hristov and is released under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 *
 */

if (typeof com == "undefined") var com = {};
if (typeof com.asual == "undefined") com.asual = {};
if (typeof com.asual.util == "undefined") com.asual.util = {};
   
/**
 * @class Utility class that provides detailed browser information.
 * @static
 * @ignore
 */
com.asual.util.Browser = new function() {

    var _supported = false;
    var _version = -1;

    var _agent = navigator.userAgent;
    var _ie = false;
    var _camino = false;
    var _safari = false;
    var _opera = false;
    var _mozilla = false;

    if (/MSIE/.test(_agent)) {
        _ie = true;
        _version = parseFloat(_agent.substring(_agent.indexOf('MSIE') + 4));
        _supported = _version >= 6;
    } else if (/AppleWebKit/.test(_agent)) {
        _safari = true;
        _version = parseFloat(_agent.substring(_agent.indexOf('Safari') + 7));
        _supported = _version >= 312;
    } else if (/Opera/.test(_agent)) {
        _opera = true;
        _version = parseFloat(navigator.appVersion);
        _supported = _version >= 9.02;
    } else if (/Camino/.test(_agent)) {
        _camino = true;
        _version = parseFloat(_agent.substring(_agent.indexOf('Camino') + 7));
        _supported = _version >= 1;
    } else if (/Firefox/.test(_agent)) {
        _mozilla = true;
        _version = parseFloat(_agent.substring(_agent.indexOf('Firefox') + 8));
        _supported = _version >= 1;
    } else if (/Netscape/.test(_agent)) {
        _mozilla = true;
        _version = parseFloat(_agent.substring(_agent.indexOf('Netscape') + 9));
        _supported = _version >= 8;
    } else if (/Mozilla/.test(_agent) && /rv:/.test(_agent)) {
        _mozilla = true;
        _version = parseFloat(_agent.substring(_agent.indexOf('rv:') + 3));
        _supported = _version >= 1.8;
    }

    /**
     * Detects if the browser is supported.
     * @return {Boolean}
     * @static
     */
    this.isSupported = function() {
        return _supported;
    }

    /**
     * Detects the version of the browser.
     * @return {Number}
     * @static
     */
    this.getVersion = function() {
        return _version;
    }

    /**
     * Detects if the browser is Internet Explorer.
     * @return {Boolean}
     * @static
     */
    this.isIE = function() {
        return _ie;
    }

    /**
     * Detects if the browser is Safari.
     * @return {Boolean}
     * @static
     */
    this.isSafari = function() {
        return _safari;
    }

    /**
     * Detects if the browser is Opera.
     * @return {Boolean}
     * @static
     */
    this.isOpera = function() {
        return _opera;
    }

    /**
     * Detects if the browser is Camino.
     * @return {Boolean}
     * @static
     */
    this.isCamino = function() {
        return _camino;
    }

    /**
     * Detects if the browser is Mozilla.
     * @return {Boolean}
     * @static
     */
    this.isMozilla = function() {
        return _mozilla;
    }
}

/**
 * @class Utility class that provides event helpers.
 * @static
 * @ignore
 */
com.asual.util.Events = new function() {

    var _cache = [];
    var _browser = com.asual.util.Browser;
    var _dcl = 'DOMContentLoaded';

    if (_browser.isIE() || _browser.isSafari()) {
        (function(){
            try {
                if (_browser.isIE() || !/loaded|complete/.test(document.readyState))
                    document.documentElement.doScroll('left');
            } catch(e) {
                return setTimeout(arguments.callee, 0);
            }
            for (var i = 0, e; e = _cache[i]; i++) {
                if (e.t == _dcl) e.l.call(null);
            }
        })();
    }

    /**
     * Adds an event listener to an object.
     * @param {Object} obj The object that provides events.
     * @param {String} type The type of the event.
     * @param {Function} listener The event listener function.
     * @return {void}
     * @static
     */
    this.addListener = function(obj, type, listener) {
        _cache.push({o: obj, t: type, l: listener});
        if (type == _dcl && (_browser.isIE() || _browser.isSafari()))
            return;
        if (obj.addEventListener){
            obj.addEventListener(type, listener, false);
        } else if (obj.attachEvent){
            obj.attachEvent('on' + type, listener);
        }
    }

    /**
     * Removes an event listener from an object.
     * @param {Object} obj The object that provides events.
     * @param {String} type The type of the event.
     * @param {Function} listener The event listener function.
     * @return {void}     
     * @static
     */
    this.removeListener = function(obj, type, listener) {
        for (var i = 0, e; e = _cache[i]; i++) {
            if (e.o == obj && e.t == type && e.l == listener) {
                _cache.splice(i, 1);
                break;
            }
        }
        if (type == _dcl && (_browser.isIE() || _browser.isSafari()))
            return;
        if (obj.removeEventListener){
            obj.removeEventListener(type, listener, false);
        } else if (obj.detachEvent){
            obj.detachEvent('on' + type, listener);
        }
    }

    var _unload = function() {
        for (var i = 0, evt; evt = _cache[i]; i++) {
            if (evt.t != _dcl)
                com.asual.util.Events.removeListener(evt.o, evt.t, evt.l);
        }
    }

    this.addListener(window, 'unload', _unload);
}

/**
 * Creates a new SWFAddress event.
 * @class Event class for SWFAddress.
 * @param {String} type Type of the event.
 */
SWFAddressEvent = function(type) {
    
    /**
     * String representation of this object.
     * @ignore
     */
    this.toString = function() {
        return '[object SWFAddressEvent]';
    }

    /**
     * The type of this event.
     * @type String
     */
    this.type = type;

    /**
     * The target of this event.
     * @type Function
     */
    this.target = [SWFAddress][0];

    /**
     * The value of this event.
     * @type String
     */
    this.value = SWFAddress.getValue();

    /**
     * The path of this event.
     * @type String
     */
    this.path = SWFAddress.getPath();

    /**
     * The parameters of this event.
     * @type Object
     */
    this.parameters = {};

    var _names = SWFAddress.getParameterNames();
    for (var i = 0, n; n = _names[i]; i++) {
        this.parameters[n] = SWFAddress.getParameter(n);
    }
}

/**
 * Init event.
 * @type String
 * @memberOf SWFAddressEvent
 * @static
 */
SWFAddressEvent.INIT = 'init';

/**
 * Change event.
 * @type String
 * @memberOf SWFAddressEvent
 * @static 
 */
SWFAddressEvent.CHANGE = 'change';

/**
 * @class The SWFAddress class can be configured with query parameters using the following format:
 * swfaddress.js?html=false&history=1&tracker=pageTracker._trackPageview&strict=1.<br /> 
 * The list of supported options include:<br /><br />
 * <code>history:Boolean</code> - Enables or disables the creation of history entries.<br />
 * <code>html:Boolean</code> - Enables or disables the usage of swfaddress.html.<br />
 * <code>strict:Boolean</code> - Enables or disables the strict mode.<br />
 * <code>tracker:String</code> - Sets a function for page view tracking.<br />
 * @static 
 */ 
SWFAddress = new function() {

    var _browser = com.asual.util.Browser;
    var _supported = _browser.isSupported();
    
    var _d = top.document;
    var _h = top.history;
    var _l = top.location;

    var _iframe, _form, _url, _js = 'swfaddress.js';
    var _title = _d.title;
    var _length = _h.length;
    var _silent = false;
    var _listeners = {};
    var _stack = [];
    var _ids = [];
    var _opts = [];
    _opts['history'] = true;
    _opts['html'] = false;
    _opts['strict'] = true;
    _opts['tracker'] = 'urchinTracker';
    
    if ((!_supported && _l.href.indexOf('#') != -1) || 
        (_browser.isSafari() && _browser.getVersion() < 412 && _l.href.indexOf('#') != -1 && _l.search != '')){
        _d.open();
        _d.write('<html><head><meta http-equiv="refresh" content="0;url=' + 
            _l.href.substr(0, _l.href.indexOf('#')) + '" /></head></html>');
        _d.close();
    }

    var _getHash = function() {
        var index = _l.href.indexOf('#');
        if (index != -1) {
            return _l.href.substring(index).replace(/^#/g, '');
        }
        return '';
    }

    var _value = _getHash();

    var _strictCheck = function(value, force) {
        if (_opts['strict']) {
            if (force) {
                if (value.substr(0, 1) != '/') value = '/' + value;
                value = value.replace(/^([^\?.]*[^\/])(\?|$)/, '$1/$2').replace(/\/\//, '/');
            } else {
                if (value == '') value = '/';
            }
        }
        return value;
    }

    var _titleCheck = function() {
        if (_browser.isIE() && _d.title != _title) {
            SWFAddress.setTitle(_title);
        }
    }

    var _listen = function() {
        if (!_silent) {
            if (_browser.isIE()) {
                if (_value != _getHash()) {
                    if (_browser.getVersion() < 7) {
                        _l.reload();
                    } else {
                        SWFAddress.setValue(_getHash());
                    }
                }
            } else if (_browser.isSafari()) {
                if (_length != _h.length) {
                    _length = _h.length;
                    if (typeof _stack[_length - 1] != 'undefined') {
                        _value = _stack[_length - 1];
                    }
                    _update();
                }
            } else if (_value != _getHash()) {
                _value = _getHash();
                _update();
            }
            _titleCheck();
        }
    }

    var _jsDispatch = function(type) {
        if (SWFAddress.hasEventListener(type)) {
            SWFAddress.dispatchEvent(new SWFAddressEvent(type));
        }
        type = type.substr(0, 1).toUpperCase() + type.substring(1);
        if(typeof SWFAddress['on' + type] == 'function') {
            SWFAddress['on' + type]();
        }
    }

    var _jsInit = function() {
        _jsDispatch('init');
    }

    var _jsChange = function() {
        _jsDispatch('change');
    }

    var _swfChange = function() {
        for (var i = 0, id; id = _ids[i]; i++) {
            var obj = document.getElementById(id);
            if (obj) {
                if (obj.parentNode && typeof obj.parentNode.so != 'undefined') {
                    obj.parentNode.so.call('setSWFAddressValue', SWFAddress.getValue());
                } else {
                    obj = (obj && typeof obj.setSWFAddressValue != 'undefined') ? 
                        obj : ((obj.getElementsByTagName('object')[0] && 
                        typeof obj.getElementsByTagName('object')[0].setSWFAddressValue != 'undefined') ? 
                        obj.getElementsByTagName('object')[0] : ((obj.getElementsByTagName('embed')[0] && 
                        typeof obj.getElementsByTagName('embed')[0].setSWFAddressValue != 'undefined') ? 
                        obj.getElementsByTagName('embed')[0] : null));
                    if (obj) {
                        obj.setSWFAddressValue(SWFAddress.getValue());
                    }
                }
            }
        }
    }

    var _update = function() {
        _swfChange();
        _jsChange();
    }

    var _track = function() {
        if (typeof _opts['tracker'] != 'undefined' && eval('typeof ' + _opts['tracker'] + ' != "undefined"')){
            var fn = eval(_opts['tracker']);
            if (typeof fn == 'function') {
                fn((_l.pathname + SWFAddress.getValue()).replace(/\/\//, '/').replace(/^\/$/, ''));
            }
        }
    }
    
    var _htmlWrite = function() {
        var doc = _iframe.contentWindow.document;
        doc.open();
        doc.write('<script>var swfaddress = "' + _getHash() + '";</script>');
        doc.close();
    }

    var _htmlLoad = function() {
        if (_opts['html']) {
            var src = _iframe.contentWindow.location.href;
            _value = (src.indexOf('?') > -1) ? 
                src.substring(src.indexOf('?') + 1) : '';
        } else {
            _value = (typeof _iframe.contentWindow.swfaddress != 'undefined') ? 
                _iframe.contentWindow.swfaddress : '';
        }
        if (_value != _getHash()) {
            _update();
            _l.hash = _value;
        }
    }

    var _load = function() {

        var attr = 'id="swfaddress" style="position:absolute;top:-9999px;"';
        if (_browser.isIE()) {
            document.body.appendChild(document.createElement('div')).innerHTML = '<iframe ' + attr + ' src="' + 
                (_opts['html'] ? _url.replace(/\.js(\?.*)?$/, '.html') + '?' + _getHash() : 'javascript:false;') + 
                '"></iframe>';
            _iframe = document.getElementById('swfaddress');
            setTimeout(function() {
                if (!_opts['html'] && typeof _iframe.contentWindow.swfaddress == 'undefined') _htmlWrite();
                com.asual.util.Events.addListener(_iframe, 'load', _htmlLoad);
            }, 10);
        } else if (_browser.isSafari()) {
            if (_browser.getVersion() < 412) {
                document.body.innerHTML += '<form ' + attr + ' method="get"></form>';
                _form = document.getElementById('swfaddress');
            }
            if (typeof _l.swfaddress == 'undefined') _l.swfaddress = {};
            if (typeof _l.swfaddress[_l.pathname] != 'undefined') _stack = _l.swfaddress[_l.pathname].split(',');
        } else if (_browser.isOpera() && _ids.length == 0) {
            document.body.innerHTML += '<embed ' + attr + ' src="' + _url.replace(/\.js(\?.*)?$/, '.swf') + 
                '" type="application/x-shockwave-flash" />';
        }
        setTimeout(_jsInit, 1);
        setTimeout(_jsChange, 2);
        setTimeout(_track, 10);
        setInterval(_listen, 50);
    }

    /**
     * Init event.
     * @type Function
     * @event
     * @static
     */
    this.onInit = null;
    
    /**
     * Change event.
     * @type Function
     * @event
     * @static
     */
    this.onChange = null;
    
    /**
     * String representation of this class.
     * @ignore
     */
    this.toString = function() {
        return '[class SWFAddress]';
    }

    /**
     * Loads the previous URL in the history list.
     * @return {void}
     * @static
     */
    this.back = function() {
        _h.back();
    }

    /**
     * Loads the next URL in the history list.
     * @return {void}
     * @static
     */
    this.forward = function() {
        _h.forward();
    }

    /**
     * Loads a URL from the history list.
     * @param {Number} delta An integer representing a relative position in the history list.
     * @return {void}
     * @static
     */
    this.go = function(delta) {
        _h.go(delta);
    }

    /**
     * Opens a new URL in the browser. 
     * @param {String} url The resource to be opened.
     * @param {String} target Target window.
     * @return {void}
     * @static
     */
    this.href = function(url, target) {
        target = typeof target != 'undefined' ? target : '_self';     
        switch(target) {
            case '_self': 
                self.location.href = url; 
                break;
            case '_top': 
                _l.href = url; 
                break;                
            case '_blank':
                window.open(url); 
                break; 
            default:
                top.frames[target].location.href = url; 
                break; 
        }
    }

    /**
     * Opens a browser popup window. 
     * @param {String} url Resource location.
     * @param {String} name Name of the popup window.
     * @param {String} options Options which get evaluted and passed to the window.open() method.
     * @param {String} handler Optional JavaScript code for popup handling.    
     * @return {void}
     * @static
     */
    this.popup = function(url, name, options, handler) {
        var popup = window.open(url, name, eval(options));
        eval(handler);
    }

    /**
     * Registers an event listener..
     * @param {String} type Event type.
     * @param {Function} listener Event listener.
     * @return {void}
     * @static
     */
    this.addEventListener = function (type, listener) {
        if (typeof _listeners[type] == 'undefined') {
            _listeners[type] = [];
        }
        _listeners[type].push(listener);
    }

    /**
     * Removes an event listener.
     * @param {String} type Event type.
     * @param {Function} listener Event listener.
     * @return {void}
     * @static     
     */
    this.removeEventListener = function (type, listener) {
        if (typeof _listeners[type] != 'undefined') {
            for (var i = 0, l; l = _listeners[type][i]; i++) {
                if (l == listener) break;
            }
            _listeners[type].splice(i, 1);
        }
    }

    /**
     * Dispatches an event to all the registered listeners. 
     * @param {Object} event Event object.
     * @return {Boolean}
     * @static
     */
    this.dispatchEvent = function (event) {
        if (typeof _listeners[event.type] != 'undefined' && _listeners[event.type].length) {
            event.target = this;
            for (var i = 0, l; l = _listeners[event.type][i]; i++) {
                l(event);
            }
            return true;           
        }
        return false;
    }

    /**
     * Checks the existance of any listeners registered for a specific type of event. 
     * @param {String} event Event type.
     * @return {Boolean}
     * @static
     */
    this.hasEventListener = function (type) {
        return (typeof _listeners[type] != 'undefined' && _listeners[type].length > 0);
    }

    /**
     * Provides the state of the strict mode setting. 
     * @return {Boolean}
     * @static
     */
    this.getStrict = function() {
        return _opts['strict'];
    }

    /**
     * Enables or disables the strict mode.
     * @param {Boolean} strict Strict mode state.
     * @return {void}
     * @static
     */
    this.setStrict = function(strict) {
        _opts['strict'] = enabled;
    }

    /**
     * Provides the state of the history setting. 
     * @return {Boolean}
     * @static
     */
    this.getHistory = function() {
        return _opts['history'];
    }

    /**
     * Enables or disables the creation of history entries.
     * @param {Boolean} history History state.
     * @return {void}
     * @static
     */
    this.setHistory = function(history) {
        _opts['history'] = history;
    }

    /**
     * Provides the tracker function.
     * @return {String}
     * @static
     */
    this.getTracker = function() {
        return _opts['tracker'];
    }

    /**
     * Sets a function for page view tracking. The default value is 'urchinTracker'.
     * @param {String} tracker Tracker function.
     * @return {void}
     * @static
     */
    this.setTracker = function(tracker) {
        _opts['tracker'] = tracker;
    }

    /**
     * Provides a list of all the Flash objects registered. 
     * @return {Array}
     * @static
     */
    this.getIds = function() {
        return _ids;
    }

    /**
     * Provides the id the first and probably the only Flash object registered. 
     * @return {String}
     * @static
     */
    this.getId = function(index) {
        return _ids[0];
    }

    /**
     * Sets the id of a single Flash object which will be registered for deep linking.
     * @param {String} id ID of the object.
     * @return {void}
     * @static
     */
    this.setId = function(id) {
        _ids[0] = id;
    }

    /**
     * Adds an id to the list of Flash object registered for deep linking.
     * @param {String} id ID of the object.
     * @return {void}
     * @static
     */
    this.addId = function(id) {
        this.removeId(id);
        _ids.push(id);
    }

    /**
     * Removes an id from the list of Flash object registered for deep linking.
     * @param {String} id ID of the object.
     * @return {void}
     * @static
     */
    this.removeId = function(id) {
        for (var i = 0, swfid; swfid = _ids[i]; i++) {
            if (id == swfid) {
                _ids.splice(i, 1);
                break;
            }
        }
    }

    /**
     * Provides the title of the HTML document.
     * @return {String}
     * @static
     */
    this.getTitle = function() {
        return _d.title;
    }

    /**
     * Sets the title of the HTML document.
     * @param {String} title Title value.
     * @return {void}
     * @static
     */
    this.setTitle = function(title) {
        if (!_supported) return null;
        if (typeof title == 'undefined') return;
        if (title == 'null') title = '';
        _title = _d.title = title;
        if (_iframe && _iframe.contentWindow)
            _iframe.contentWindow.document.title = title;
    }

    /**
     * Provides the status of the browser window.
     * @return {String}
     * @static
     */
    this.getStatus = function() {
        return top.status;
    }

    /**
     * Sets the status of the browser window.
     * @param {String} status Status value.
     * @return {void}
     * @static
     */
    this.setStatus = function(status) {
        if (!_supported) return null;
        if (typeof status == 'undefined') return;
        if (!_browser.isSafari()) {
            if (status == 'null') status = '';
            status = _strictCheck(status, true);
            if (status == '/') status = '';
            if (!(/http(s)?:\/\//.test(status))) {
                var index = _l.href.indexOf('#');
                status = (index == -1 ? _l.href : _l.href.substr(0, index)) + '#' + status;
            }
            top.status = status;
        }
    }

    /**
     * Resets the status of the browser window.
     * @return {void}
     * @static
     */
    this.resetStatus = function() {
        top.status = '';
    }

    /**
     * Provides the current deep linking value.
     * @return {String}
     * @static
     */
    this.getValue = function() {
        if (!_supported) return null;
        return _strictCheck(_value, false);
    }

    /**
     * Sets the current deep linking value.
     * @param {String} value A value which will be appended to the base link of the HTML document.
     * @return {void}
     * @static
     */
    this.setValue = function(value) {
        if (!_supported) return null;
        if (typeof value == 'undefined') return;
        if (value == 'null') value = ''
        value = _strictCheck(value, true);
        if (value == '/') value = '';
        if (_value == value) return;
        _value = value;
        _silent = true;
        _update();
        _stack[_h.length] = _value;
        if (_browser.isSafari()) {
            if (_opts['history']) {
                _l.swfaddress[_l.pathname] = _stack.toString();
                _length = _h.length + 1;
                if (_browser.getVersion() < 412) {
                    if (_l.search == '') {
                        _form.action = '#' + _value;
                        _form.submit();
                    }
                } else {
                    var evt = document.createEvent('MouseEvents');
                    evt.initEvent('click', true, true);
                    var anchor = document.createElement('a');
                    anchor.href = '#' + _value;
                    anchor.dispatchEvent(evt);
                }
            } else {
                _l.replace('#' + _value);
            }
        } else if (_value != _getHash()) {
            if (_opts['history']) {
                _l.hash = '#' + _value;
            } else {
                _l.replace('#' + _value);
            }
        }
        if (_browser.isIE() && _opts['history']) {
            if (_opts['html']) {
                _iframe.contentWindow.location.assign(_iframe.contentWindow.location.pathname + 
                    '?' + _getHash());
            } else {
                _htmlWrite();
            }
        }
        setTimeout(_track, 10);
        _silent = false;
    }

    /**
     * Provides the deep linking value without the query string.
     * @return {String}
     * @static
     */
    this.getPath = function() {
        var value = this.getValue();
        if (value.indexOf('?') != -1) {
            return value.split('?')[0];
        } else {
            return value;   
        }
    }

    /**
     * Provides the query string part of the deep linking value.
     * @return {String}
     * @static
     */
    this.getQueryString = function() {
        var value = this.getValue();
        var index = value.indexOf('?');
        if (index != -1 && index < value.length) {
            return value.substr(index + 1);
        }
        return '';
    }

    /**
     * Provides the value of a specific query parameter.
     * @param {String} param Parameter name.
     * @return {String}
     * @static
     */
    this.getParameter = function(param) {
        var value = this.getValue();
        var index = value.indexOf('?');
        if (index != -1) {
            value = value.substr(index + 1);
            var params = value.split('&');
            var p, i = params.length;
            while(i--) {
                p = params[i].split('=');
                if (p[0] == param) {
                    return p[1];
                }
            }
        }
        return '';
    }

    /**
     * Provides a list of all the query parameter names.
     * @return {Array}
     * @static
     */
    this.getParameterNames = function() {
        var value = this.getValue();
        var index = value.indexOf('?');
        var names = [];
        if (index != -1) {
            value = value.substr(index + 1);
            if (value != '' && value.indexOf('=') != -1) {
                var params = value.split('&');
                var i = 0;
                while(i < params.length) {
                    names.push(params[i].split('=')[0]);
                    i++;
                }
            }
        }
        return names;
    }

    if (!_supported) return;
    
    for (var i = 1; i < _length; i++) {
        _stack.push('');
    }
    _stack.push(_l.hash.replace(/^#/g, ''));

    if (_browser.isIE() && _l.hash != _getHash()) {
        _l.hash = '#' + _getHash();
    }

    var scripts = document.getElementsByTagName('script');
    for (var i = 0, s; s = scripts[i]; i++) {
        if (s.src.indexOf(_js) > -1) {
            _url = String(s.src);
            break;
        }
    }
    if ((qi = _url.indexOf('?')) > -1) {
        var param, params = _url.substr(qi + 1).split('&');
        for (var j = 0, p; p = params[j]; j++) {
            param = p.split('=');
            if (/^(history|html|strict)$/.test(param[0])) {
                _opts[param[0]] = (isNaN(param[1]) ? eval(param[1]) : (parseFloat(param[1]) > 0));
            }
            if (/^tracker$/.test(param[0])) {
                _opts[param[0]] = param[1];
            }
        }
    }
    if (/file:\/\//.test(_l.href)) _opts['html'] = false;

    _titleCheck();
    com.asual.util.Events.addListener(document, 'DOMContentLoaded', _load);
}

/* Flash embedding hooks */
if (typeof swfobject != 'undefined') SWFObject = swfobject;
if (typeof FlashObject != 'undefined') SWFObject = FlashObject;
if (typeof SWFObject != 'undefined') {
    if (SWFObject.prototype && SWFObject.prototype.write) {
        com.asual.SWFObjectWrite = SWFObject.prototype.write;
        /**
         * @ignore
         */
        SWFObject.prototype.write = function() {
            if (this.getAttribute('version').major < 8) {
                this.addVariable('$swfaddress', SWFAddress.getValue());
                ((typeof arguments[0] == 'string') ? 
                    document.getElementById(arguments[0]) : arguments[0]).so = this;
            }
            if (success = com.asual.SWFObjectWrite.apply(this, arguments))
                SWFAddress.addId(this.getAttribute('id'));
            return success;
        }
    } else {
        com.asual.SWFObjectRegisterObject = SWFObject.registerObject;
        SWFObject.registerObject = function() {
            com.asual.SWFObjectRegisterObject.apply(this, arguments);
            SWFAddress.addId(arguments[0]);            
        }
        com.asual.SWFObjectCreateSWF = SWFObject.createSWF;
        SWFObject.createSWF = function() {
            com.asual.SWFObjectCreateSWF.apply(this, arguments);
            SWFAddress.addId(arguments[0].id);            
        }
        com.asual.SWFObjectEmbedSWF = SWFObject.embedSWF;
        SWFObject.embedSWF = function() {
            com.asual.SWFObjectEmbedSWF.apply(this, arguments);
            SWFAddress.addId(arguments[8].id);            
        }
    }
}
if (typeof UFO != 'undefined') {
    com.asual.UFOCreate = UFO.create;
    UFO.create = function() {
        com.asual.UFOCreate.apply(this, arguments);
        SWFAddress.addId(arguments[0].id);        
    }
}
if (typeof AC_FL_RunContent != 'undefined') {
    com.asual.AC_FL_RunContent = AC_FL_RunContent;
    AC_FL_RunContent = function() {
        com.asual.AC_FL_RunContent.apply(this, arguments);
        for (var i = 0, a; a = arguments[i]; i++) {
            if (a == 'id') {
                SWFAddress.addId(arguments[i+1]);
                break;
            }
        }
    }
}
