/*! 
 * flowplayer.js @VERSION. The Flowplayer API
 * 
 * Copyright 2010 Flowplayer Oy
 * 
 * This file is part of Flowplayer.
 * 
 * Flowplayer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * Flowplayer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with Flowplayer.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Date: @DATE
 * Revision: @REVISION 
 */
(function() {
 
/* 
    FEATURES 
    --------
    - $f() and flowplayer() functions    
    - handling multiple instances 
    - Flowplayer programming API 
    - Flowplayer event model    
    - player loading / unloading    
    - jQuery support
*/ 
 

/*jslint glovar: true, browser: true */
/*global flowplayer, $f */

// {{{ private utility methods
    
    function log(args) {
        console.log("$f.fireEvent", [].slice.call(args));    
    }

        
    // thanks: http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
    function clone(obj) {    
        if (!obj || typeof obj != 'object') { return obj; }        
        var temp = new obj.constructor();    
        for (var key in obj) {    
            if (obj.hasOwnProperty(key)) {
                temp[key] = clone(obj[key]);
            }
        }        
        return temp;
    }

    // stripped from jQuery, thanks John Resig 
    function each(obj, fn) {
        if (!obj) { return; }
        
        var name, i = 0, length = obj.length;
    
        // object
        if (length === undefined) {
            for (name in obj) {
                if (fn.call(obj[name], name, obj[name]) === false) { break; }
            }
            
        // array
        } else {
            for (var value = obj[0];
                i < length && fn.call( value, i, value ) !== false; value = obj[++i]) {                
            }
        }
    
        return obj;
    }

    
    // convenience
    function el(id) {
        return document.getElementById(id);     
    }    

    
    // used extensively. a very simple implementation. 
    function extend(to, from, skipFuncs) {
        if (typeof from != 'object') { return to; }
        
        if (to && from) {            
            each(from, function(name, value) {
                if (!skipFuncs || typeof value != 'function') {
                    to[name] = value;        
                }
            });
        }
        
        return to;
    }
    
    // var arr = select("elem.className"); 
    function select(query) {
        var index = query.indexOf("."); 
        if (index != -1) {
            var tag = query.slice(0, index) || "*";
            var klass = query.slice(index + 1, query.length);
            var els = [];
            each(document.getElementsByTagName(tag), function() {
                if (this.className && this.className.indexOf(klass) != -1) {
                    els.push(this);        
                }
            });
            return els;
        }
    }
    
    // fix event inconsistencies across browsers
    function stopEvent(e) {
        e = e || window.event;
        
        if (e.preventDefault) {
            e.stopPropagation();
            e.preventDefault();
            
        } else {
            e.returnValue = false;    
            e.cancelBubble = true;
        } 
        return false;
    }

    // push an event listener into existing array of listeners
    function bind(to, evt, fn) {
        to[evt] = to[evt] || [];
        to[evt].push(fn);        
    }
    
    
    // generates an unique id
   function makeId() {
      return "_" + ("" + Math.random()).slice(2, 10);   
   }
    
//}}}    
    

// {{{ Clip

    var Clip = function(json, index, player) {
        
        // private variables
        var self = this,
             cuepoints = {},
             listeners = {};
             
        self.index = index;
        
        // instance variables
        if (typeof json == 'string') {
            json = {url:json};    
        }
    
        extend(this, json, true);    
        
        // event handling 
        each(("Begin*,Start,Pause*,Resume*,Seek*,Stop*,Finish*,LastSecond,Update,BufferFull,BufferEmpty,BufferStop").split(","),
            function() {
            
            var evt = "on" + this;
                
            // before event
            if (evt.indexOf("*") != -1) {
                evt = evt.slice(0, evt.length -1); 
                var before = "onBefore" + evt.slice(2); 
                
                self[before] = function(fn) {
                    bind(listeners, before, fn);
                    return self;
                };                
            }  
            
            self[evt] = function(fn) {
                bind(listeners, evt, fn);
                return self;
            };
            
            
            // set common clip event listeners to player level
            if (index == -1) {
                if (self[before]) {
                    player[before] = self[before];        
                }                
                if (self[evt])  {
                    player[evt] = self[evt];        
                }
            }
            
        });              
        
        extend(this, { 
             
            onCuepoint: function(points, fn) {    
                
                // embedded cuepoints
                if (arguments.length == 1) {
                    cuepoints.embedded = [null, points];
                    return self;
                }
                
                if (typeof points == 'number') {
                    points = [points];    
                }
                
                var fnId = makeId();  
                cuepoints[fnId] = [points, fn]; 
                
                if (player.isLoaded()) {
                    player._api().fp_addCuepoints(points, index, fnId);    
                }  
                
                return self;
            },
            
            update: function(json) {
                extend(self, json);

                if (player.isLoaded()) {
                    player._api().fp_updateClip(json, index);    
                }
                var conf = player.getConfig(); 
                var clip = (index == -1) ? conf.clip : conf.playlist[index];
                extend(clip, json, true);
            },
            
            
            // internal event for performing clip tasks. should be made private someday
            _fireEvent: function(evt, arg1, arg2, target) {                 
                if (evt == 'onLoad') { 
                    each(cuepoints, function(key, val) {
                        if (val[0]) {
                            player._api().fp_addCuepoints(val[0], index, key);         
                        }
                    }); 
                    return false;
                }
                
                // target clip we are working against
                target = target || self;    
                
                if (evt == 'onCuepoint') {
                    var fn = cuepoints[arg1];
                    if (fn) {
                        return fn[1].call(player, target, arg2);
                    }
                }  

                // 1. clip properties, 2-3. metadata, 4. updates, 5. resumes from nested clip
                if (arg1 && "onBeforeBegin,onMetaData,onStart,onUpdate,onResume".indexOf(evt) != -1) {                    
                    // update clip properties
                    extend(target, arg1);                    
                    
                    if (arg1.metaData) {
                        if (!target.duration) {
                            target.duration = arg1.metaData.duration;     
                        } else {
                            target.fullDuration = arg1.metaData.duration;    
                        }                      
                    }
                }                  
                

                var ret = true;
                each(listeners[evt], function() {
                    ret = this.call(player, target, arg1, arg2);        
                }); 
                return ret;                
            }            
            
        });
        
        
        // get cuepoints from config
        if (json.onCuepoint) {
            var arg = json.onCuepoint;
            self.onCuepoint.apply(self, typeof arg == 'function' ? [arg] : arg);
            delete json.onCuepoint;
        } 
        
        // get other events
        each(json, function(key, val) {
            
            if (typeof val == 'function') {
                bind(listeners, key, val);
                delete json[key];
            }
            
        });

        
        // setup common clip event callbacks for Player object too (shortcuts)
        if (index == -1) {
            player.onCuepoint = this.onCuepoint;    
        }

    };

//}}}


// {{{ Plugin
        
    var Plugin = function(name, json, player, fn) {
    
        var self = this,
             listeners = {},
             hasMethods = false;
    
        if (fn) {
            extend(listeners, fn);    
        }   
        
        // custom callback functions in configuration
        each(json, function(key, val) {
            if (typeof val == 'function') {
                listeners[key] = val;
                delete json[key];    
            }
        });  
        
        // core plugin methods        
        extend(this, {
  
            // speed and fn are optional
            animate: function(props, speed, fn) { 
                if (!props) {
                    return self;    
                }
                
                if (typeof speed == 'function') { 
                    fn = speed; 
                    speed = 500;
                }
                
                if (typeof props == 'string') {
                    var key = props;
                    props = {};
                    props[key] = speed;
                    speed = 500; 
                }
                
                if (fn) {
                    var fnId = makeId();
                    listeners[fnId] = fn;
                }
        
                if (speed === undefined) { speed = 500; }
                json = player._api().fp_animate(name, props, speed, fnId);    
                return self;
            },
            
            css: function(props, val) {
                if (val !== undefined) {
                    var css = {};
                    css[props] = val;
                    props = css;                    
                }
                json = player._api().fp_css(name, props);
                extend(self, json);
                return self;
            },
            
            show: function() {
                this.display = 'block';
                player._api().fp_showPlugin(name);
                return self;
            },
            
            hide: function() {
                this.display = 'none';
                player._api().fp_hidePlugin(name);
                return self;
            },
            
            // toggle between visible / hidden state
            toggle: function() {
                this.display = player._api().fp_togglePlugin(name);
                return self;
            },            
            
            fadeTo: function(o, speed, fn) {
                
                if (typeof speed == 'function') { 
                    fn = speed; 
                    speed = 500;
                }
                
                if (fn) {
                    var fnId = makeId();
                    listeners[fnId] = fn;
                }                
                this.display = player._api().fp_fadeTo(name, o, speed, fnId);
                this.opacity = o;
                return self;
            },
            
            fadeIn: function(speed, fn) { 
                return self.fadeTo(1, speed, fn);                
            },
    
            fadeOut: function(speed, fn) {
                return self.fadeTo(0, speed, fn);    
            },
            
            getName: function() {
                return name;    
            },
            
            getPlayer: function() {
                return player;    
            },
            
            // internal method. should be made private some day
         _fireEvent: function(evt, arg, arg2) {
                
            // update plugins properties & methods
            if (evt == 'onUpdate') {
               var json = player._api().fp_getPlugin(name); 
                    if (!json) { return;    }                    
                    
               extend(self, json);
               delete self.methods;
                    
               if (!hasMethods) {
                  each(json.methods, function() {
                     var method = "" + this;       
                            
                     self[method] = function() {
                        var a = [].slice.call(arguments);
                        var ret = player._api().fp_invoke(name, method, a); 
                        return ret === 'undefined' || ret === undefined ? self : ret;
                     };
                  });
                  hasMethods = true;         
               }
            }
            
            // plugin callbacks
            var fn = listeners[evt];

            if (fn) {
                var ret = fn.apply(self, arg);
                    
                // "one-shot" callback
                if (evt.slice(0, 1) == "_") {
                    delete listeners[evt];  
                } 
                
                return ret;
            }
            
            return self;
         }
            
        });

    };


//}}}


function Player(wrapper, params, conf) {   
    
    // private variables (+ arguments)
    var self = this, 
        api = null, 
        isUnloading = false,
        html, 
        commonClip, 
        playlist = [], 
        plugins = {},
        listeners = {},
        playerId,
        apiId,
        
        // n'th player on the page
        playerIndex,
        
        // active clip's index number
        activeIndex,
        
        swfHeight,
        wrapperHeight;    

  
// {{{ public methods 
    
    extend(self, {
            
        id: function() {
            return playerId;    
        }, 
        
        isLoaded: function() {
            return (api !== null && api["fp_play"] != undefined && ! isUnloading);    
        },
        
        getParent: function() {
            return wrapper;    
        },
        
        hide: function(all) {
            if (all) { wrapper.style.height = "0px"; }
            if (self.isLoaded()) { api.style.height = "0px"; } 
            return self;
        },

        show: function() {
            wrapper.style.height = wrapperHeight + "px";
            if (self.isLoaded()) { api.style.height = swfHeight + "px"; }
            return self;
        }, 
                    
        isHidden: function() {
            return self.isLoaded() && parseInt(api.style.height, 10) === 0;
        },
        
        load: function(fn) { 

            if (!self.isLoaded() && self._fireEvent("onBeforeLoad") !== false) {
                
                var onPlayersUnloaded = function() {
                    html = wrapper.innerHTML;                
                
                    // do not use splash as alternate content for flashembed
                    if (html && !flashembed.isSupported(params.version)) {
                        wrapper.innerHTML = "";                    
                    }                  
                
                    // install Flash object inside given container
                    flashembed(wrapper, params, {config: conf});
                
                    // onLoad listener given as argument
                    if (fn) {
                        fn.cached = true;
                        bind(listeners, "onLoad", fn);    
                    }
                };
                
                
                // unload all instances
                var unloadedPlayersNb = 0;
                each(players, function()  {
                    this.unload(function(wasUnloaded) {
                        if ( ++unloadedPlayersNb == players.length ) {
                            onPlayersUnloaded();
                        }
                    });        
                });
            }
            
            return self;    
        },
        
        unload: function(fn) {
            
            
            // if we are fullscreen on safari, we can't unload as it would crash the PluginHost, sorry
            if (this.isFullscreen() && /WebKit/i.test(navigator.userAgent)) {
                if ( fn ) { fn(false); }
                return self;
            }
            
            
            // unload only if in splash state
            if (html.replace(/\s/g,'') !== '') {
                
                if (self._fireEvent("onBeforeUnload") === false) {
                    if ( fn ) { fn(false); }
                    return self;
                }    
                
                isUnloading = true;
                // try closing
                try {
                    if (api) { 
                        api.fp_close();
                        
                        // fire unload only when API is present
                        self._fireEvent("onUnload");
                    }                
                } catch (error) {}                
                
                var clean = function() {
                    api = null;                
                    wrapper.innerHTML = html;
                    isUnloading = false;
                    
                    if ( fn ) { fn(true); }
                };
                
                setTimeout(clean, 50);            
            } 
            else if ( fn ) { fn(false); }
            
            return self;
        
        },
        
        getClip: function(index) {
            if (index === undefined) {
                index = activeIndex;    
            }
            return playlist[index];
        },
        
        
        getCommonClip: function() {
            return commonClip;    
        },        
        
        getPlaylist: function() {
            return playlist; 
        },
        
      getPlugin: function(name) {  
         var plugin = plugins[name];
         
            // create plugin if nessessary
         if (!plugin && self.isLoaded()) {
                var json = self._api().fp_getPlugin(name);
                if (json) {
                    plugin = new Plugin(name, json, self);
                    plugins[name] = plugin;                          
                } 
         }        
         return plugin; 
      },
        
        getScreen: function() { 
            return self.getPlugin("screen");
        }, 
        
        getControls: function() { 
            return self.getPlugin("controls")._fireEvent("onUpdate");
        }, 
        
        // 3.2
        getLogo: function() {
            try {
                return self.getPlugin("logo")._fireEvent("onUpdate");
            } catch (ignored) {}
        },
        
        // 3.2
        getPlay: function() {
            return self.getPlugin("play")._fireEvent("onUpdate");
        },
        

        getConfig: function(copy) { 
            return copy ? clone(conf) : conf;
        },
        
        getFlashParams: function() { 
            return params;
        },        
        
        loadPlugin: function(name, url, props, fn) { 

            // properties not supplied            
            if (typeof props == 'function') { 
                fn = props; 
                props = {};
            } 
            
            // if fn not given, make a fake id so that plugin's onUpdate get's fired
            var fnId = fn ? makeId() : "_"; 
            self._api().fp_loadPlugin(name, url, props, fnId); 
            
            // create new plugin
            var arg = {};
            arg[fnId] = fn;
            var p = new Plugin(name, null, self, arg);
            plugins[name] = p;
            return p;            
        },
        
        
        getState: function() {
            return self.isLoaded() ? api.fp_getState() : -1;
        },
        
        // "lazy" play
        play: function(clip, instream) {
            
            var p = function() {
                if (clip !== undefined) {
                    self._api().fp_play(clip, instream);
                } else {
                    self._api().fp_play();    
                }
            };
            
            if (self.isLoaded()) {
                p();    
            } else if ( isUnloading ) {
                setTimeout(function() { 
                    self.play(clip, instream); 
                }, 50);
                
            } else {
                self.load(function() { 
                    p();
                });
            }
            
            return self;
        },
        
        getVersion: function() {
            var js = "flowplayer.js @VERSION";
            if (self.isLoaded()) {
                var ver = api.fp_getVersion();
                ver.push(js);
                return ver;
            }
            return js; 
        },
        
        _api: function() {
            if (!self.isLoaded()) {
                throw "Flowplayer " +self.id()+ " not loaded when calling an API method";
            }
            return api;                
        },
        
        setClip: function(clip) {
            self.setPlaylist([clip]);
            return self;
        },
        
        getIndex: function() {
            return playerIndex;    
        }
        
    }); 
    
    
    // event handlers
    each(("Click*,Load*,Unload*,Keypress*,Volume*,Mute*,Unmute*,PlaylistReplace,ClipAdd,Fullscreen*,FullscreenExit,Error,MouseOver,MouseOut").split(","),
        function() {         
            var name = "on" + this;
            
            // before event
            if (name.indexOf("*") != -1) {
                name = name.slice(0, name.length -1); 
                var name2 = "onBefore" + name.slice(2);
                self[name2] = function(fn) {
                    bind(listeners, name2, fn);    
                    return self;
                };                        
            }
            
            // normal event
            self[name] = function(fn) {
                bind(listeners, name, fn);    
                return self;
            };             
        }
    ); 
    
    
    // core API methods
    each(("pause,resume,mute,unmute,stop,toggle,seek,getStatus,getVolume,setVolume,getTime,isPaused,isPlaying,startBuffering,stopBuffering,isFullscreen,toggleFullscreen,reset,close,setPlaylist,addClip,playFeed,setKeyboardShortcutsEnabled,isKeyboardShortcutsEnabled").split(","),        
        function() {         
            var name = this;
            
            self[name] = function(a1, a2) {
                if (!self.isLoaded()) { return self; }
                var ret = null;
                
                // two arguments
                if (a1 !== undefined && a2 !== undefined) { 
                    ret = api["fp_" + name](a1, a2);
                    
                } else { 
                    ret = (a1 === undefined) ? api["fp_" + name]() : api["fp_" + name](a1);
                }
                
                return ret === 'undefined' || ret === undefined ? self : ret;
            };             
        }
    );         
    
//}}}


// {{{ public method: _fireEvent
        
    self._fireEvent = function(a) {        
        
        if (typeof a == 'string') { a = [a]; }
        
        var evt = a[0], arg0 = a[1], arg1 = a[2], arg2 = a[3], i = 0;          
        
        if (conf.debug) { log(a); }                
        
        // internal onLoad
        if (!self.isLoaded() && evt == 'onLoad' && arg0 == 'player') {                        
            
            api = api || el(apiId); 
            swfHeight = api.clientHeight;
            
            each(playlist, function() {
                this._fireEvent("onLoad");        
            });
            
            each(plugins, function(name, p) {
                p._fireEvent("onUpdate");        
            }); 
            
            commonClip._fireEvent("onLoad");  
        }
        
        // other onLoad events are skipped
        if (evt == 'onLoad' && arg0 != 'player') { return; }
        
        
        // "normalize" error handling
        if (evt == 'onError') { 
            if (typeof arg0 == 'string' || (typeof arg0 == 'number' && typeof arg1 == 'number'))  {
                arg0 = arg1;
                arg1 = arg2;
            }             
        }
        
        
      if (evt == 'onContextMenu') {
         each(conf.contextMenu[arg0], function(key, fn)  {
            fn.call(self);
         });
         return;
      }

        if (evt == 'onPluginEvent' || evt == 'onBeforePluginEvent') { 
            var name = arg0.name || arg0;
            var p = plugins[name];

            if (p) {
                p._fireEvent("onUpdate", arg0);
                return p._fireEvent(arg1, a.slice(3));        
            }
            return;
        }        

        // replace whole playlist
        if (evt == 'onPlaylistReplace') {
            playlist = [];
            var index = 0;
            each(arg0, function() {
                playlist.push(new Clip(this, index++, self));
            });        
        }
        
        // insert new clip to the playlist. arg0 = clip, arg1 = index 
        if (evt == 'onClipAdd') {
            
            // instream clip additions are ignored at this point
            if (arg0.isInStream) { return; }
            
            // add new clip into playlist            
            arg0 = new Clip(arg0, arg1, self);
            playlist.splice(arg1, 0, arg0);
            
            // increment index variable for the rest of the clips on playlist 
            for (i = arg1 + 1; i < playlist.length; i++) {
                playlist[i].index++;    
            }
        }
        
        
        var ret = true;
        
        // clip event
        if (typeof arg0 == 'number' && arg0 < playlist.length) {
            
            activeIndex = arg0;
            var clip = playlist[arg0];            
            
            if (clip) {
                ret = clip._fireEvent(evt, arg1, arg2);    
            } 
            
            if (!clip || ret !== false) {

                // clip argument is given for common clip, because it behaves as the target
                ret = commonClip._fireEvent(evt, arg1, arg2, clip);    
            }  
        }
        
        
        // trigger player event
        each(listeners[evt], function() {
            ret = this.call(self, arg0, arg1);        
            
            // remove cached entry
            if (this.cached) {
                listeners[evt].splice(i, 1);    
            }
            
            // break loop
            if (ret === false) { return false;     }
            i++;
            
        }); 

        return ret;
    };

//}}}
 

// {{{ init
    
   function init() {
        
        // replace previous installation 
        if ($f(wrapper)) {
            $f(wrapper).getParent().innerHTML = ""; 
            playerIndex = $f(wrapper).getIndex();
            players[playerIndex] = self;
            
        // register this player into global array of instances
        } else {
            players.push(self);
            playerIndex = players.length -1;
        }
        
        wrapperHeight = parseInt(wrapper.style.height, 10) || wrapper.clientHeight;     
        
        // playerId    
        playerId = wrapper.id || "fp" + makeId();
        apiId = params.id || playerId + "_api";
        params.id = apiId;
        conf.playerId = playerId;
        

        // plain url is given as config
        if (typeof conf == 'string') {
            conf = {clip:{url:conf}};    
        } 
        
        if (typeof conf.clip == 'string') {
            conf.clip = {url: conf.clip};    
        }
        
        // common clip is always there
        conf.clip = conf.clip || {};  
        
        
        // wrapper href as common clip's url
        if (wrapper.getAttribute("href", 2) && !conf.clip.url) { 
            conf.clip.url = wrapper.getAttribute("href", 2);            
        } 
        
        commonClip = new Clip(conf.clip, -1, self); 
        
        // playlist
        conf.playlist = conf.playlist || [conf.clip]; 
        
        var index = 0;
        
        each(conf.playlist, function() {
            
            var clip = this;            
            
            /* sometimes clip is given as array. this is not accepted. */
            if (typeof clip == 'object' && clip.length) {
                clip = {url: "" + clip};    
            }            
            
            // populate common clip properties to each clip
            each(conf.clip, function(key, val) {
                if (val !== undefined && clip[key] === undefined && typeof val != 'function') {
                    clip[key] = val;    
                }
            });    
            
            // modify playlist in configuration
            conf.playlist[index] = clip;            
            
            // populate playlist array
            clip = new Clip(clip, index, self);
            playlist.push(clip);                        
            index++;            
        });                
        
        // event listeners
        each(conf, function(key, val) {
            if (typeof val == 'function') {
                
                // common clip event
                if (commonClip[key]) {
                    commonClip[key](val);
                    
                // player event
                } else {
                    bind(listeners, key, val);    
                }                
                
                // no need to supply for the Flash component
                delete conf[key];    
            }
        });         
        
        
        // plugins
        each(conf.plugins, function(name, val) {
            if (val) {
                plugins[name] = new Plugin(name, val, self);
            }
        });
        
        
        // setup controlbar plugin if not explicitly defined
        if (!conf.plugins || conf.plugins.controls === undefined) {
            plugins.controls = new Plugin("controls", null, self);    
        }
        
        // setup canvas as plugin
        plugins.canvas = new Plugin("canvas", null, self);        
        
        // click function
        function doClick(e) { 
            if (!self.isLoaded() && self._fireEvent("onBeforeClick") !== false) {
                self.load();        
            } 
            return stopEvent(e);                    
        }
        
        // defer loading upon click
        html = wrapper.innerHTML;
        if (html.replace(/\s/g, '') !== '') {     
            
            if (wrapper.addEventListener) {
                wrapper.addEventListener("click", doClick, false);    
                
            } else if (wrapper.attachEvent) {
                wrapper.attachEvent("onclick", doClick);    
            }
            
        // player is loaded upon page load 
        } else {
            
            // prevent default action from wrapper. (fixes safari problems)
            if (wrapper.addEventListener) {
                wrapper.addEventListener("click", stopEvent, false);    
            }
            // load player
            self.load();
        }
    }

    // possibly defer initialization until DOM get's loaded
    if (typeof wrapper == 'string') { 
        var node = el(wrapper); 
            
        if (!node) {
            throw "Flowplayer cannot access element: " + wrapper;    
        } else {
            wrapper = node; 
            init();                    
        } 
        
    // we have a DOM element so page is already loaded
    } else {        
        init();
    }
    
    
//}}}


}


// {{{ flowplayer() & statics 

// container for player instances
var players = [];


// this object is returned when multiple player's are requested 
function Iterator(arr) {
    
    this.length = arr.length;
    
    this.each = function(fn)  {
        each(arr, fn);    
    };
    
    this.size = function() {
        return arr.length;    
    };    
}

// these two variables are the only global variables
window.flowplayer = window.$f = function() {

    var instance = null;
    var arg = arguments[0];    
    
    // $f()
    if (!arguments.length) {
        each(players, function() {
            if (this.isLoaded())  {
                instance = this;    
                return false;
            }
        });
        
        return instance || players[0];
    } 
    
    if (arguments.length == 1) {
        
        // $f(index);
        if (typeof arg == 'number') { 
            return players[arg];    
    
            
        // $f(wrapper || 'containerId' || '*');
        } else {
            
            // $f("*");
            if (arg == '*') {
                return new Iterator(players);    
            }
            
            // $f(wrapper || 'containerId');
            each(players, function() {
                if (this.id() == arg.id || this.id() == arg || this.getParent() == arg)  {
                    instance = this;    
                    return false;
                }
            });
            
            return instance;                    
        }
    }             

    // instance builder 
    if (arguments.length > 1) {        

        // flashembed parameters
        var params = arguments[1],
             conf = (arguments.length == 3) ? arguments[2] : {};
                     
        
        if (typeof params == 'string') {
            params = {src: params};    
        } 
        
        params = extend({
            bgcolor: "#000000",
            version: [9, 0],
            expressInstall: "http://static.flowplayer.org/swf/expressinstall.swf",
            cachebusting: true
            
        }, params);        
        
        if (typeof arg == 'string') {
            
            // select arg by classname
            if (arg.indexOf(".") != -1) {
                var instances = [];
                
                each(select(arg), function() { 
                    instances.push(new Player(this, clone(params), clone(conf)));         
                });    
                
                return new Iterator(instances);
                
            // select node by id
            } else {        
                var node = el(arg);
                return new Player(node !== null ? node : arg, params, conf);      
            } 
            
            
        // arg is a DOM element
        } else if (arg) {
            return new Player(arg, params, conf);                        
        }
        
    } 
    
    return null; 
};
    
extend(window.$f, {

    // called by Flash External Interface         
    fireEvent: function() {
        var a = [].slice.call(arguments);
        var p = $f(a[0]);        
        return p ? p._fireEvent(a.slice(1)) : null;
    },
    
    
    // create plugins by modifying Player's prototype
    addPlugin: function(name, fn) {
        Player.prototype[name] = fn;
        return $f;
    },
    
    // utility methods for plugin developers
    each: each,
    
    extend: extend
    
});

    
//}}}


//{{{ jQuery support

if (typeof jQuery == 'function') {
    
    jQuery.fn.flowplayer = function(params, conf) {  
        
        // select instances
        if (!arguments.length || typeof arguments[0] == 'number') {
            var arr = [];
            this.each(function()  {
                var p = $f(this);
                if (p) {
                    arr.push(p);    
                }
            });
            return arguments.length ? arr[arguments[0]] : new Iterator(arr);
        }
        
        // create flowplayer instances
        return this.each(function() { 
            $f(this, clone(params), conf ? clone(conf) : {});    
        }); 
        
    };
    
}

//}}}


})();
/**
 * flowplayer.controls.js [3.0.2]. Flowplayer JavaScript plugin.
 * 
 * This file is part of Flowplayer, http://flowplayer.org
 *
 * Author: Tero Piirainen, <support@flowplayer.org>
 * Copyright (c) 2008 Flowplayer Ltd
 *
 * Dual licensed under MIT and GPL 2+ licenses
 * SEE: http://www.opensource.org/licenses
 * 
 * Version: @VERSION - $Date
 */
$f.addPlugin("controls", function(wrap, options) {
    
        
//{{{ private functions
        
    function fixE(e) {
        if (typeof e == 'undefined') { e = window.event; }
        if (typeof e.layerX == 'undefined') { e.layerX = e.offsetX; }
        if (typeof e.layerY == 'undefined') { e.layerY = e.offsetY; }
        return e;
    }
    
    function w(e) {
        return e.clientWidth;    
    }
    
    function offset(e) {
        return e.offsetLeft;    
    }
    
    /* a generic dragger utility for hoirzontal dragging */
    function Draggable(o, min, max, offset) { 
        
        var dragging = false;
        
        function foo() { }
        
        o.onDragStart    = o.onDragStart || foo;
        o.onDragEnd        = o.onDragEnd      || foo;
        o.onDrag            = o.onDrag          || foo;    
        
        function move(x) {
            // must be withing [min, max]
            if (x > max) { return false; }
            if (x < min) { return false; } 
            o.style.left = x + "px";    
            return true;
        }
        
        function end() {
            document.onmousemove = null;
            document.onmouseup   = null;
            o.onDragEnd(parseInt(o.style.left, 10));
            dragging = false;
        }

        function drag(e) {
            e = fixE(e); 
            var x = e.clientX - offset; 
            if (move(x)) {
                dragging = true;
                o.onDrag(x);        
            } 
            return false;
        }
        
        o.onmousedown = function(e)  {
            e = fixE(e);
            o.onDragStart(parseInt(o.style.left, 10)); 
            document.onmousemove        = drag;
            document.onmouseup        = end;
            return false;    
        };
        
        this.dragTo = function(x) {
            if (move(x)) {
                o.onDragEnd(x);        
            }    
        };
        
        this.setMax = function(val) {
            max = val;    
        };
        
        this.isDragging = function() {
            return dragging;    
        };

        return this; 
    }

    function extend(to, from) {
        if (from) {
            for (key in from) {
                if (key) {
                    to[key] = from[key];        
                } 
            }
        }
    }
    
    function byClass(name) {
        var els = wrap.getElementsByTagName("*");        
        var re = new RegExp("(^|\\s)" + name + "(\\s|$)");
        for (var i = 0; i < els.length; i++) {
            if (re.test(els[i].className)) {
                return els[i];
            }
        }
    }
    
    // prefix integer with zero when nessessary 
    function pad(val) {
        val = parseInt(val, 10);
        return val >= 10 ? val : "0" + val;
    }
    
    // display seconds in hh:mm:ss format
    function toTime(sec) {
        
        var h = Math.floor(sec / 3600);
        var min = Math.floor(sec / 60);
        sec = sec - (min * 60);
        
        if (h >= 1) {
            min -= h * 60;
            return pad(h) + ":" + pad(min) + ":" + pad(sec);
        }
        
        return pad(min) + ":" + pad(sec);
    }
    
    function getTime(time, duration) {
        return "<span>" + toTime(time) + "</span> <strong>" + toTime(duration) + "</strong>";    
    }
    
//}}}
    
    
    var self = this;
    
    var opts = {
        playHeadClass: 'playhead',
        trackClass: 'track',
        playClass: 'play',
        pauseClass: 'pause',
        bufferClass: 'buffer',
        progressClass: 'progress',
        
        timeClass: 'time',
        muteClass: 'mute',
        unmuteClass: 'unmute',
        duration: 0,        
        
        template: '<a class="play">play</a>' + 
                     '<div class="track">' +
                         '<div class="buffer"></div>' +
                         '<div class="progress"></div>' +
                         '<div class="playhead"></div>' +
                     '</div>' + 
                     '<div class="time"></div>' +
                     '<a class="mute">mute</a>'                 
    };
    
    extend(opts, options);
    
    if (typeof wrap == 'string') {
        wrap = document.getElementById(wrap);
    }
    
    if (!wrap) { return;    }
    
    // inner HTML
    if (!wrap.innerHTML.replace(/\s/g, '')) {
        wrap.innerHTML = opts.template;        
    }     
    
    // get elements 
    var ball = byClass(opts.playHeadClass);
    var bufferBar = byClass(opts.bufferClass);
    var progressBar = byClass(opts.progressClass);
    var track = byClass(opts.trackClass);
    var time = byClass(opts.timeClass);
    var mute = byClass(opts.muteClass);
    
    
    // initial time
    time.innerHTML = getTime(0, opts.duration);
    
    // get dimensions 
    var trackWidth = w(track);
    var ballWidth = w(ball); 
    
    // initialize draggable playhead
    var head = new Draggable(ball, 0, 0, offset(wrap) + offset(track) + (ballWidth / 2)); 
    
    // track click moves playHead    
    track.onclick = function(e) {
        e = fixE(e);
        if (e.target == ball) { return false; }
        head.dragTo(e.layerX - ballWidth / 2);
    };
    
    // play/pause button
    var play = byClass(opts.playClass);
    
    play.onclick = function() {
        if (self.isLoaded()) {
            self.toggle();        
        } else {
            self.play();    
        }                        
    };
    
    // mute/unmute button
    mute.onclick = function() {
        if (self.getStatus().muted)  {
            self.unmute();    
        } else {
            self.mute();    
        }
    };

    // setup timer
    var timer = null;
    
    function getMax(len, total) {
        return parseInt(Math.min(len / total * trackWidth, trackWidth - ballWidth / 2), 10);    
    }
    
    self.onStart(function(clip) {
        
        var duration = clip.duration || 0;

        // clear previous timer        
        clearInterval(timer);
         
        // begin timer        
        timer = setInterval(function()  {            
            
            var status = self.getStatus();            

            // time display
            if (status.time)  {                
                time.innerHTML = getTime(status.time, clip.duration);    
            } 
            
            if (status.time === undefined) {
                clearInterval(timer);
                return;
            }
            
            // buffer width
            var x = getMax(status.bufferEnd, duration);
            bufferBar.style.width = x + "px";
            head.setMax(x);    
        
            
            
            // progress width
            if (!self.isPaused() && !head.isDragging()) {
                x = getMax(status.time, duration);
                progressBar.style.width = x + "px";
                ball.style.left = (x -ballWidth / 2) + "px";
            }
            
        }, 500);
    });
    
    self.onBegin(function() {
        play.className = opts.pauseClass;        
    });

    
    // pause / resume states    
    self.onPause(function() {
        play.className = opts.playClass;
    });

    self.onResume(function() {
        play.className = opts.pauseClass;
    });
    
    
    // mute / unmute states    
    self.onMute(function() {
        mute.className = opts.unmuteClass;
    });

    self.onUnmute(function() {
        mute.className = opts.muteClass;
    });
    
    
    // clear timer when clip ends    
    self.onFinish(function(clip) {        
        clearInterval(timer);    
    }); 
    
    self.onUnload(function() {
        time.innerHTML = getTime(0, opts.duration);
    });
    
    
    ball.onDragEnd = function(x) {
        var to = parseInt(x / trackWidth  * 100, 10) + "%";
        progressBar.style.width = x + "px";
        if (self.isLoaded()) {
            self.seek(to);        
        } 
    };
    
    ball.onDrag = function(x) {
        progressBar.style.width = x + "px";    
    };

    
    // return player instance to enable plugin chaining
    return self;
    
});
        
            
            

/**
 * flowplayer.embed.js [3.0.2]. Flowplayer JavaScript plugin.
 * 
 * This file is part of Flowplayer, http://flowplayer.org
 *
 * Author: Tero Piirainen, <support@flowplayer.org>
 * Copyright (c) 2008 Flowplayer Ltd
 *
 * Dual licensed under MIT and GPL 2+ licenses
 * SEE: http://www.opensource.org/licenses
 * 
 * Version: @VERSION - $Date
 */
(function() {

    // converts paths to absolute URL's as required in external sites 
    function toAbsolute(url, base) {
        
        // http://some.com/path
        if (url.substring(0, 4) == "http") { return url; }
        
        if (base) {            
            return base + (base.substring(base.length -1) != "/" ? "/" : "") + url; 
        }
        
        // /some/path
        base = location.protocol + "//" + location.host;        
        if (url.substring(0, 1) == "/") { return base + url; }
        
        // yet/another/path        
        var path = location.pathname;        
        path = path.substring(0, path.lastIndexOf("/"));
        return base + path + "/" + url;
    }
    
    
    // Flowplayer plugin implementation
    $f.addPlugin("embed", function(options) {
    
        var self = this;
        var conf = self.getConfig(true);

        
        // default configuration for flashembed
        var opts = {
            width: self.getParent().clientWidth || '100%',
            height: self.getParent().clientHeight || '100%',
            url: toAbsolute(self.getFlashParams().src), 
            index: -1,
            allowfullscreen: true,
            allowscriptaccess: 'always',
            id: "_" + self.id()
        };         
        
        // override defaults
        $f.extend(opts, options);
        opts.src = opts.url;
        opts.w3c = true;
        
        
        // not needed for external objects
        delete conf.playerId;        
        delete opts.url;
        delete opts.index;
        
        
        // construct HTML code for the configuration
        this.getEmbedCode = function(runnable, index) {            
            
            // selected clip only: given in argument or in configuration
            index = typeof index == 'number' ? index : opts.index;
            if (index >= 0) {
                conf.playlist = [ self.getPlaylist()[index] ];    
            }
            
            // setup absolute path for each clip
            index = 0;
            $f.each(conf.playlist, function() {
                conf.playlist[index++].url = toAbsolute(this.url, this.baseUrl);
            });            
            
            var html = flashembed.getHTML(opts, {config: conf});
            
            if (!runnable)  {
                html = html.replace(/\</g, "&lt;").replace(/\>/g, "&gt;");     
            }                
                
            return html;            
        };
        
        return self;
        
    });
    
})();        
/*!
 * flowplayer.playlist @VERSION. Flowplayer JavaScript plugin.
 * 
 * This file is part of Flowplayer, http://flowplayer.org
 *
 * Author: Tero Piirainen, <info@flowplayer.org>
 * Copyright (c) 2008-2010 Flowplayer Ltd
 *
 * Dual licensed under MIT and GPL 2+ licenses
 * SEE: http://www.opensource.org/licenses
 * 
 * Date: @DATE
 * Revision: @REVISION 
 */ 
(function($) {
    
    $f.addPlugin("playlist", function(wrap, options) {


        // self points to current Player instance
        var self = this;    
        
        var opts = {
            playingClass: 'playing',
            pausedClass: 'paused',
            progressClass:'progress',
            template: '<a href="${url}">${title}</a>',
            loop: false,
            playOnClick: true,
            manual: false
        };        
        
        $.extend(opts, options);
        wrap = $(wrap);        
        var manual = self.getPlaylist().length <= 1 || opts.manual; 
        var els = null;
        
        
//{{{ "private" functions
                
        function toString(clip) {
            var el = template;
            
            $.each(clip, function(key, val) {    
                if (!$.isFunction(val)) {
                    el = el.replace("$\{" +key+ "\}", val).replace("$%7B" +key+ "%7D", val);            
                }
            }); 
            return el;
        }
        
        // assign onClick event for each clip
        function bindClicks() {            
            els = getEls().unbind("click.playlist").bind("click.playlist", function() {
                return play($(this), els.index(this));                        
            });        
        }
        
        function buildPlaylist() {
            wrap.empty();
            
            $.each(self.getPlaylist(), function() {  
                wrap.append(toString(this)); 
            });                
            
            bindClicks();
        } 

        
        function play(el, clip)  {
        
            if (el.hasClass(opts.playingClass) || el.hasClass(opts.pausedClass)) {
                self.toggle();
                
            } else {
                el.addClass(opts.progressClass);
                self.play(clip);                             
            }            
            
            return false;
        }    
        
        
        function clearCSS() {
            if (manual) { els = getEls(); }
            els.removeClass(opts.playingClass);
            els.removeClass(opts.pausedClass);
            els.removeClass(opts.progressClass);            
        }
        
        function getEl(clip) {
            return (manual) ? els.filter("[href=" + clip.originalUrl + "]") : els.eq(clip.index);    
        }
        
        function getEls() {
            var els = wrap.find("a");
            return els.length ? els : wrap.children();
        }
//}}}  
         
        /* setup playlists with onClick handlers */ 
        
        // internal playlist
        if (!manual) {
            
            var template = wrap.is(":empty") ? opts.template : wrap.html(); 
            buildPlaylist();            
            
            
        // manual playlist
        } else {
            
            els = getEls();            
            
            // allows dynamic addition of elements
            if ($.isFunction(els.live)) {
                var foo = $(wrap.selector + " a");
                if (!foo.length) { foo = $(wrap.selector + " > *"); }
                
                foo.live("click", function() {
                    var el = $(this);
                    return play(el, el.attr("href"));
                });
                
            } else {
                els.click(function() {
                    var el = $(this);
                    return play(el, el.attr("href"));
                });                    
            }
                         
                    
            // setup player to play first clip
            var clip = self.getClip(0);
            if (!clip.url && opts.playOnClick) {
                clip.update({url: els.eq(0).attr("href")});        
            }   
            
        }
        
        // onBegin
        self.onBegin(function(clip) {
            clearCSS();        
            getEl(clip).addClass(opts.playingClass);
        });    
        
        // onPause    
        self.onPause(function(clip) {
            getEl(clip).removeClass(opts.playingClass).addClass(opts.pausedClass);        
        });    
        
        // onResume
        self.onResume(function(clip) {
            getEl(clip).removeClass(opts.pausedClass).addClass(opts.playingClass);        
        });        
        
        // what happens when clip ends ?
        if (!opts.loop && !manual) {
            
            // stop the playback exept on the last clip, which is stopped by default
            self.onBeforeFinish(function(clip) {
                if (!clip.isInStream && clip.index < els.length -1) {
                    return false;
                }
            }); 
        }
        
        // on manual setups perform looping here
        if (manual && opts.loop) {
            self.onBeforeFinish(function(clip) {
                var el = getEl(clip);
                if (el.next().length) {
                    el.next().click();             
                } else {
                    els.eq(0).click();    
                } 
                return false;                
            }); 
        }
        
        // onUnload
        self.onUnload(function() {
            clearCSS();        
        });
        
        // onPlaylistReplace
        if (!manual) {
            self.onPlaylistReplace(function() {
                buildPlaylist();        
            });
        }
        
        // onClipAdd
        self.onClipAdd(function(clip, index) {    
            els.eq(index).before(toString(clip));            
            bindClicks(); 
        });        
        
        return self;
        
    });
        
})(jQuery);        

var site = {

    uploadDone: function(fileName, hostId) {
        var img = hostId ? $("div.hostPicture[hostId=" + hostId + "] img") : $("#picture");
        img.attr("src", "http://flowplayer-users.s3.amazonaws.com/" + fileName + "?_=" + Math.random());
    },

    submitForm: function(form, to) {
        form = $(form);
        form.fadeTo(400, 0.3);

        $.getJSON(form.attr("action") + "?" + form.serialize(), function(json) {
            form.fadeTo(400, 1);

            if (json.message) {
                form.find("div.error").html(json.message).show();

            } else {
                if (to)  {
                    location.href = to;
                } else  {
                    location.reload();
                }
            }
        });

        return false;
    },

    setCookie: function(name, value, days) {
        var c = name + "=" + escape(value);

        if (days) {
            var today = new Date();
            var expiry = new Date(today.getTime() + days * 1000 * 60 * 60 * 24);
            c += ";expires=" + expiry.toGMTString();
        }
        document.cookie = c + ";path=/";
    }

}


$(function() {

    $("#logout").click(function() {
        $.get("/account/logout", function() {
            location.reload();
        });
        return false;
    });

//{{{ messy highlighting stuff


    // get the folder ("f")
    var els = location.pathname.split("/"),
         f = "/" + els[1],
         isTools = f.indexOf('/tools') != -1;

    if (f.indexOf("#") != -1) f = f.substring(0, f.indexOf("#"));

    // the switch
    $("#global_fp, #global_jt").eq(isTools ? 1 : 0).addClass("active");

    // navigation
    if (f == '/index.html' || f == '/') f = "";

    if (isTools) {
        $("#nav2 a").filter("[href=" + location.pathname + "]").addClass("active");
    } else {
        $("#nav1 a").filter("[href=" + f + "/index.html]").addClass("active");
    }


    // hightlight subnav
    var loc = location.href;
    var page = loc.substring(loc.indexOf("/", 10), loc.indexOf("?") > 0 ? loc.indexOf("?") : loc.length);
    if (page.indexOf("#") != -1) {
        page = page.substring(0, page.indexOf("#"));
    }

    el = $("#right ul a[href=" +page+ "]");
    if (!el.length && (f == 'documentation' || f == 'account')) el = $("#right ul a:first");

    el.addClass("selected").click(function(e) {
        e.preventDefault();
    });

    // remove redundant borders from subnav
    $("#right ul").each(function() {
        $(this).find("a:last").css("borderBottom", 0);
    });


    // setup main title background image
    f = f.substring(1);

    if (f == 'plugins' && els[2] && els[2] != 'index.html') {
        f = els[2];
        if (els[1] == 'tools') f = "tools";
    }

    if (f == 'demos') {
        f = "documentation";
    }

    var title = $("#content h1:first");
    if (f && title.length && title.css("backgroundImage") == 'none') {
        if (f == 'admin') f = 'flowplayer';
        title.css("backgroundImage", "url(http://static.flowplayer.org/img/title/" + f + ".png)");
    }
    //}}}


    // lazy download of jquery.chili.js
    var sourceCode = $("code[class]");
    
    if (!$.browser.msie && sourceCode.length) {
        $.getScript("/js/highlight.min.js", function() { 
             sourceCode.each(function() {
                var el = $(this),
                     lang = el.attr("className"),
                     hl = new DlHighlight({ 
                         lang: lang == "javascript" ? "js" : lang, 
                         lineNumbers: false 
                     }); 
                     
                el.addClass("DlHighlight").html(hl.doItNow($.trim(el.text())));
             });
        });
    }

    // button.custom, span.play hover and mousedown
    $("button.custom").each(function() {
        var el = $(this);
        if (!el.find("span").length) el.html("<span>" + el.html() + "</span>");
    });

    $("button.custom, span.play").each(function()  {

        var el = $(this);
        var xPos = el.attr("id") == 'searchButton' ? '-100px' : '0';

    });

    $("a.player").hover(function() {
        $("img", this).fadeTo(400, 1);
    }, function() {
        $("img", this).fadeTo(400, 0.7);

    }).find("img").css({opacity:0.7});


    $("#latestPosts a").click(function() {
        $("#latestPosts a").removeClass("selected");
        $(this).addClass("selected");
    });


    // download statistics
    $(".download").each(function()  {
        var el = $(this), href = el.attr("href");
        href = href.substring(href.lastIndexOf("/") + 1);

        el.click(function() {
            _tracker._trackEvent("Download", location.pathname, href);

        }).bind("contextmenu", function() {
            _tracker._trackEvent("Download", location.pathname, href);

        });
    });


//{{{ login / signup / logout

    $(".account input").focus(function() {
        var el = $(this);
        if (this.name == 'password' && el.attr("type") != 'password') {
            var el2 = $('<input/>').attr("type", "password").attr("name", "password");
            el.after(el2);
            el.remove();
            el2.focus();
        }
        this.select();

    }).blur(function() {
        if (!this.value) { this.value = this.name; }
    });

    // login / forgot password scrollable
    $("#loginscroll").scrollable({ next: '#anext', prev: '#aprev' });

    // toggle login / signup
    $("#acc a").each(function(i)  {         

        var a = $(this);

        a.mouseover(function() {
            a.addClass("active");
        });

        a.tooltip({
            tip: i == 0 ? '#loginscroll' : '#signup',
            position: 'bottom right',
            offset: [-10, i == 0 ? -45 : -52],
            events: {
                tooltip: 'mouseover'
            },

            onShow: function(e) {
                a.addClass("active");
                $(i > 0 ? '#loginscroll' : '#signup').hide();
            },
            onBeforeHide: function(e, i) {
                a.removeClass("active");
            }
        });
    });

    function closeAcc() {
        var panel = $("#acc .active").data("tooltip");
        if (panel) { panel.hide(); }
        $("#acc a").removeClass("active");
    }

    $(document).click(function(e) {
        var el = $(e.target)
        if ($(".account:visible").length && !el.is(".account") && !el.parents(".account").length && !el.is("#acc a")) {
            closeAcc();
        }
    });

    $(document).keydown(function(e) {
        if (e.keyCode == 27) { closeAcc(); }
    });


    function formSubmit(form, action, fn) {

        form = $(form).fadeTo(400, 0.6);

        // error container
        var err = form.find(".error");
        if (!err.length) { err = $("<p></p>").addClass("error"); form.append(err); }
        err.hide();

        $.post(action + "?" + form.serialize(), function(res) {
            form.fadeTo(200, 1);

            res = eval("(" + res + ")");
            if (res.message) {
                err.html(res.message).show();
                setTimeout(function() { err.slideUp(); }, 3000);
            } else {
                if (typeof fn == 'string') { err.html(fn).show(); }
                else { fn.call(); }
            }
        });

        return false;
    }

    $.formSubmit = formSubmit;

    // login
    $("#login").submit(function() {
        return formSubmit(this, "/account/login", function()  {
            if (location.href.indexOf("download") != -1) {
                location.href = "/account/products.html";
            } else {
                location.reload();
            }
        });
    });


    $("#signup").submit(function() {
        return formSubmit(this, "/account/create",
            "Your account was successfully created. Check out your mail for further details."
        );
    });

    $("#forgot").submit(function() {
        return formSubmit(this, "/account/requestPassword", "An activation link has been sent to your email account");
    });
    
//}}}



    var tweets = $("#tweets"), 
         twitterAcc = isTools ? "jquerytools" : "flowplayer", 
         re = /(http:[^\s]+)/;

    if (tweets.length) {
        
        function prettyDate(dateStr) {
    
            var date = new Date(dateStr);
    
            if (date == 'NaN')  {
                return dateStr.substring(0, 11);
            }
    
            var diff = (((new Date()).getTime() - date.getTime()) / 1000),
                 day_diff = Math.floor(diff / 86400);
    
            if (isNaN(day_diff) || day_diff < 0) return dateStr;
    
    
            return day_diff == 0 && (
                     diff < 60 && "just now" ||
                     diff < 120 && "1 minute ago" ||
                     diff < 3600 && Math.floor( diff / 60 ) + " minutes ago" ||
                     diff < 7200 && "1 hour ago" ||
                     diff < 86400 && Math.floor( diff / 3600 ) + " hours ago") ||
                     day_diff == 1 && "Yesterday" ||
                     day_diff < 7 && day_diff + " days ago" ||
                     Math.ceil( day_diff / 7 ) + " weeks ago";
        }        

        $.getJSON("/twitter/" + twitterAcc + ".json", function(json) {
        
            $.each(json, function(index, item)  {
                if (index > 3) return false; 
                var time = prettyDate(item.created_at),
                     text = item.text.replace(re, '<a href="$1">$1</a>');
                tweets.append("<div class='tweet'><p>" + text + "</p><span class='time'>" + time + "</span></div>");
            });

            tweets.find("p").click(function() {
                location.href = $(this).find("a").attr("href");
            });
        });
    }

});


var _gat=new Object({c:"length",lb:"4.3",m:"cookie",b:undefined,cb:function(d,a){this.zb=d;this.Nb=a},r:"__utma=",W:"__utmb=",ma:"__utmc=",Ta:"__utmk=",na:"__utmv=",oa:"__utmx=",Sa:"GASO=",X:"__utmz=",lc:"http://www.google-analytics.com/__utm.gif",mc:"https://ssl.google-analytics.com/__utm.gif",Wa:"utmcid=",Ya:"utmcsr=",$a:"utmgclid=",Ua:"utmccn=",Xa:"utmcmd=",Za:"utmctr=",Va:"utmcct=",Hb:false,_gasoDomain:undefined,_gasoCPath:undefined,e:window,a:document,k:navigator,t:function(d){var a=1,c=0,h,
o;if(!_gat.q(d)){a=0;for(h=d[_gat.c]-1;h>=0;h--){o=d.charCodeAt(h);a=(a<<6&268435455)+o+(o<<14);c=a&266338304;a=c!=0?a^c>>21:a}}return a},C:function(d,a,c){var h=_gat,o="-",k,l,s=h.q;if(!s(d)&&!s(a)&&!s(c)){k=h.w(d,a);if(k>-1){l=d.indexOf(c,k);if(l<0)l=d[h.c];o=h.F(d,k+h.w(a,"=")+1,l)}}return o},Ea:function(d){var a=false,c=0,h,o;if(!_gat.q(d)){a=true;for(h=0;h<d[_gat.c];h++){o=d.charAt(h);c+="."==o?1:0;a=a&&c<=1&&(0==h&&"-"==o||_gat.P(".0123456789",o))}}return a},d:function(d,a){var c=encodeURIComponent;
return c instanceof Function?(a?encodeURI(d):c(d)):escape(d)},J:function(d,a){var c=decodeURIComponent,h;d=d.split("+").join(" ");if(c instanceof Function)try{h=a?decodeURI(d):c(d)}catch(o){h=unescape(d)}else h=unescape(d);return h},Db:function(d){return d&&d.hash?_gat.F(d.href,_gat.w(d.href,"#")):""},q:function(d){return _gat.b==d||"-"==d||""==d},Lb:function(d){return d[_gat.c]>0&&_gat.P(" \n\r\t",d)},P:function(d,a){return _gat.w(d,a)>-1},h:function(d,a){d[d[_gat.c]]=a},T:function(d){return d.toLowerCase()},
z:function(d,a){return d.split(a)},w:function(d,a){return d.indexOf(a)},F:function(d,a,c){c=_gat.b==c?d[_gat.c]:c;return d.substring(a,c)},uc:function(){var d=_gat.b,a=window;if(a&&a.gaGlobal&&a.gaGlobal.hid)d=a.gaGlobal.hid;else{d=Math.round(Math.random()*2147483647);a.gaGlobal=a.gaGlobal?a.gaGlobal:{};a.gaGlobal.hid=d}return d},wa:function(){return Math.round(Math.random()*2147483647)},Gc:function(){return(_gat.wa()^_gat.vc())*2147483647},vc:function(){var d=_gat.k,a=_gat.a,c=_gat.e,h=a[_gat.m]?
a[_gat.m]:"",o=c.history[_gat.c],k,l,s=[d.appName,d.version,d.language?d.language:d.browserLanguage,d.platform,d.userAgent,d.javaEnabled()?1:0].join("");if(c.screen)s+=c.screen.width+"x"+c.screen.height+c.screen.colorDepth;else if(c.java){l=java.awt.Toolkit.getDefaultToolkit().getScreenSize();s+=l.screen.width+"x"+l.screen.height}s+=h;s+=a.referrer?a.referrer:"";k=s[_gat.c];while(o>0)s+=o--^k++;return _gat.t(s)}});_gat.hc=function(){var d=this,a=_gat.cb;function c(h,o){return new a(h,o)}d.db="utm_campaign";d.eb="utm_content";d.fb="utm_id";d.gb="utm_medium";d.hb="utm_nooverride";d.ib="utm_source";d.jb="utm_term";d.kb="gclid";d.pa=0;d.I=0;d.wb="15768000";d.Tb="1800";d.ea=[];d.ga=[];d.Ic="cse";d.Gb="q";d.ab="google";d.fa=[c(d.ab,d.Gb),c("yahoo","p"),c("msn","q"),c("aol","query"),c("aol","encquery"),c("lycos","query"),c("ask","q"),c("altavista","q"),c("netscape","query"),c("cnn","query"),c("looksmart","qt"),c("about",
"terms"),c("mamma","query"),c("alltheweb","q"),c("gigablast","q"),c("voila","rdata"),c("virgilio","qs"),c("live","q"),c("baidu","wd"),c("alice","qs"),c("yandex","text"),c("najdi","q"),c("aol","q"),c("club-internet","query"),c("mama","query"),c("seznam","q"),c("search","q"),c("wp","szukaj"),c("onet","qt"),c("netsprint","q"),c("google.interia","q"),c("szukacz","q"),c("yam","k"),c("pchome","q"),c("kvasir","searchExpr"),c("sesam","q"),c("ozu","q"),c("terra","query"),c("nostrum","query"),c("mynet","q"),
c("ekolay","q"),c("search.ilse","search_for")];d.B=undefined;d.Kb=false;d.p="/";d.ha=100;d.Da="/__utm.gif";d.ta=1;d.ua=1;d.G="|";d.sa=1;d.qa=1;d.pb=1;d.g="auto";d.D=1;d.Ga=1000;d.Yc=10;d.nc=10;d.Zc=0.2};_gat.Y=function(d,a){var c,h,o,k,l,s,q,f=this,n=_gat,w=n.q,x=n.c,g,z=a;f.a=d;function B(i){var b=i instanceof Array?i.join("."):"";return w(b)?"-":b}function A(i,b){var e=[],j;if(!w(i)){e=n.z(i,".");if(b)for(j=0;j<e[x];j++)if(!n.Ea(e[j]))e[j]="-"}return e}function p(){return u(63072000000)}function u(i){var b=new Date,e=new Date(b.getTime()+i);return"expires="+e.toGMTString()+"; "}function m(i,b){f.a[n.m]=i+"; path="+z.p+"; "+b+f.Cc()}function r(i,b,e){var j=f.V,t,v;for(t=0;t<j[x];t++){v=j[t][0];
v+=w(b)?b:b+j[t][4];j[t][2](n.C(i,v,e))}}f.Jb=function(){return n.b==g||g==f.t()};f.Ba=function(){return l?l:"-"};f.Wb=function(i){l=i};f.Ma=function(i){g=n.Ea(i)?i*1:"-"};f.Aa=function(){return B(s)};f.Na=function(i){s=A(i)};f.Hc=function(){return g?g:"-"};f.Cc=function(){return w(z.g)?"":"domain="+z.g+";"};f.ya=function(){return B(c)};f.Ub=function(i){c=A(i,1)};f.K=function(){return B(h)};f.La=function(i){h=A(i,1)};f.za=function(){return B(o)};f.Vb=function(i){o=A(i,1)};f.Ca=function(){return B(k)};
f.Xb=function(i){k=A(i);for(var b=0;b<k[x];b++)if(b<4&&!n.Ea(k[b]))k[b]="-"};f.Dc=function(){return q};f.Uc=function(i){q=i};f.pc=function(){c=[];h=[];o=[];k=[];l=n.b;s=[];g=n.b};f.t=function(){var i="",b;for(b=0;b<f.V[x];b++)i+=f.V[b][1]();return n.t(i)};f.Ha=function(i){var b=f.a[n.m],e=false;if(b){r(b,i,";");f.Ma(f.t());e=true}return e};f.Rc=function(i){r(i,"","&");f.Ma(n.C(i,n.Ta,"&"))};f.Wc=function(){var i=f.V,b=[],e;for(e=0;e<i[x];e++)n.h(b,i[e][0]+i[e][1]());n.h(b,n.Ta+f.t());return b.join("&")};
f.bd=function(i,b){var e=f.V,j=z.p,t;f.Ha(i);z.p=b;for(t=0;t<e[x];t++)if(!w(e[t][1]()))e[t][3]();z.p=j};f.dc=function(){m(n.r+f.ya(),p())};f.Pa=function(){m(n.W+f.K(),u(z.Tb*1000))};f.ec=function(){m(n.ma+f.za(),"")};f.Ra=function(){m(n.X+f.Ca(),u(z.wb*1000))};f.fc=function(){m(n.oa+f.Ba(),p())};f.Qa=function(){m(n.na+f.Aa(),p())};f.cd=function(){m(n.Sa+f.Dc(),"")};f.V=[[n.r,f.ya,f.Ub,f.dc,"."],[n.W,f.K,f.La,f.Pa,""],[n.ma,f.za,f.Vb,f.ec,""],[n.oa,f.Ba,f.Wb,f.fc,""],[n.X,f.Ca,f.Xb,f.Ra,"."],[n.na,
f.Aa,f.Na,f.Qa,"."]]};_gat.jc=function(d){var a=this,c=_gat,h=d,o,k=function(l){var s=(new Date).getTime(),q;q=(s-l[3])*(h.Zc/1000);if(q>=1){l[2]=Math.min(Math.floor(l[2]*1+q),h.nc);l[3]=s}return l};a.O=function(l,s,q,f,n,w,x){var g,z=h.D,B=q.location;if(!o)o=new c.Y(q,h);o.Ha(f);g=c.z(o.K(),".");if(g[1]<500||n){if(w)g=k(g);if(n||!w||g[2]>=1){if(!n&&w)g[2]=g[2]*1-1;g[1]=g[1]*1+1;l="?utmwv="+_gat.lb+"&utmn="+c.wa()+(c.q(B.hostname)?"":"&utmhn="+c.d(B.hostname))+(h.ha==100?"":"&utmsp="+c.d(h.ha))+l;if(0==z||2==z){var A=
new Image(1,1);A.src=h.Da+l;var p=2==z?function(){}:x||function(){};A.onload=p}if(1==z||2==z){var u=new Image(1,1);u.src=("https:"==B.protocol?c.mc:c.lc)+l+"&utmac="+s+"&utmcc="+a.wc(q,f);u.onload=x||function(){}}}}o.La(g.join("."));o.Pa()};a.wc=function(l,s){var q=[],f=[c.r,c.X,c.na,c.oa],n,w=l[c.m],x;for(n=0;n<f[c.c];n++){x=c.C(w,f[n]+s,";");if(!c.q(x))c.h(q,f[n]+x+";")}return c.d(q.join("+"))}};_gat.i=function(){this.la=[]};_gat.i.bb=function(d,a,c,h,o,k){var l=this;l.cc=d;l.Oa=a;l.L=c;l.sb=h;l.Pb=o;l.Qb=k};_gat.i.bb.prototype.S=function(){var d=this,a=_gat.d;return"&"+["utmt=item","utmtid="+a(d.cc),"utmipc="+a(d.Oa),"utmipn="+a(d.L),"utmiva="+a(d.sb),"utmipr="+a(d.Pb),"utmiqt="+a(d.Qb)].join("&")};_gat.i.$=function(d,a,c,h,o,k,l,s){var q=this;q.v=d;q.ob=a;q.bc=c;q.ac=h;q.Yb=o;q.ub=k;q.$b=l;q.xb=s;q.ca=[]};_gat.i.$.prototype.mb=function(d,a,c,h,o){var k=this,l=k.Eb(d),s=k.v,q=_gat;if(q.b==
l)q.h(k.ca,new q.i.bb(s,d,a,c,h,o));else{l.cc=s;l.Oa=d;l.L=a;l.sb=c;l.Pb=h;l.Qb=o}};_gat.i.$.prototype.Eb=function(d){var a,c=this.ca,h;for(h=0;h<c[_gat.c];h++)a=d==c[h].Oa?c[h]:a;return a};_gat.i.$.prototype.S=function(){var d=this,a=_gat.d;return"&"+["utmt=tran","utmtid="+a(d.v),"utmtst="+a(d.ob),"utmtto="+a(d.bc),"utmttx="+a(d.ac),"utmtsp="+a(d.Yb),"utmtci="+a(d.ub),"utmtrg="+a(d.$b),"utmtco="+a(d.xb)].join("&")};_gat.i.prototype.nb=function(d,a,c,h,o,k,l,s){var q=this,f=_gat,n=q.xa(d);if(f.b==
n){n=new f.i.$(d,a,c,h,o,k,l,s);f.h(q.la,n)}else{n.ob=a;n.bc=c;n.ac=h;n.Yb=o;n.ub=k;n.$b=l;n.xb=s}return n};_gat.i.prototype.xa=function(d){var a,c=this.la,h;for(h=0;h<c[_gat.c];h++)a=d==c[h].v?c[h]:a;return a};_gat.gc=function(d){var a=this,c="-",h=_gat,o=d;a.Ja=screen;a.qb=!self.screen&&self.java?java.awt.Toolkit.getDefaultToolkit():h.b;a.a=document;a.e=window;a.k=navigator;a.Ka=c;a.Sb=c;a.tb=c;a.Ob=c;a.Mb=1;a.Bb=c;function k(){var l,s,q,f,n="ShockwaveFlash",w="$version",x=a.k?a.k.plugins:h.b;if(x&&x[h.c]>0)for(l=0;l<x[h.c]&&!q;l++){s=x[l];if(h.P(s.name,"Shockwave Flash"))q=h.z(s.description,"Shockwave Flash ")[1]}else{n=n+"."+n;try{f=new ActiveXObject(n+".7");q=f.GetVariable(w)}catch(g){}if(!q)try{f=
new ActiveXObject(n+".6");q="WIN 6,0,21,0";f.AllowScriptAccess="always";q=f.GetVariable(w)}catch(z){}if(!q)try{f=new ActiveXObject(n);q=f.GetVariable(w)}catch(z){}if(q){q=h.z(h.z(q," ")[1],",");q=q[0]+"."+q[1]+" r"+q[2]}}return q?q:c}a.xc=function(){var l;if(self.screen){a.Ka=a.Ja.width+"x"+a.Ja.height;a.Sb=a.Ja.colorDepth+"-bit"}else if(a.qb)try{l=a.qb.getScreenSize();a.Ka=l.width+"x"+l.height}catch(s){}a.Ob=h.T(a.k&&a.k.language?a.k.language:(a.k&&a.k.browserLanguage?a.k.browserLanguage:c));a.Mb=
a.k&&a.k.javaEnabled()?1:0;a.Bb=o?k():c;a.tb=h.d(a.a.characterSet?a.a.characterSet:(a.a.charset?a.a.charset:c))};a.Xc=function(){return"&"+["utmcs="+h.d(a.tb),"utmsr="+a.Ka,"utmsc="+a.Sb,"utmul="+a.Ob,"utmje="+a.Mb,"utmfl="+h.d(a.Bb)].join("&")}};_gat.n=function(d,a,c,h,o){var k=this,l=_gat,s=l.q,q=l.b,f=l.P,n=l.C,w=l.T,x=l.z,g=l.c;k.a=a;k.f=d;k.Rb=c;k.ja=h;k.o=o;function z(p){return s(p)||"0"==p||!f(p,"://")}function B(p){var u="";p=w(x(p,"://")[1]);if(f(p,"/")){p=x(p,"/")[1];if(f(p,"?"))u=x(p,"?")[0]}return u}function A(p){var u="";u=w(x(p,"://")[1]);if(f(u,"/"))u=x(u,"/")[0];return u}k.Fc=function(p){var u=k.Fb(),m=k.o;return new l.n.s(n(p,m.fb+"=","&"),n(p,m.ib+"=","&"),n(p,m.kb+"=","&"),k.ba(p,m.db,"(not set)"),k.ba(p,m.gb,"(not set)"),
k.ba(p,m.jb,u&&!s(u.R)?l.J(u.R):q),k.ba(p,m.eb,q))};k.Ib=function(p){var u=A(p),m=B(p);if(f(u,k.o.ab)){p=x(p,"?").join("&");if(f(p,"&"+k.o.Gb+"="))if(m==k.o.Ic)return true}return false};k.Fb=function(){var p,u,m=k.Rb,r,i,b=k.o.fa;if(z(m)||k.Ib(m))return;p=A(m);for(r=0;r<b[g];r++){i=b[r];if(f(p,w(i.zb))){m=x(m,"?").join("&");if(f(m,"&"+i.Nb+"=")){u=x(m,"&"+i.Nb+"=")[1];if(f(u,"&"))u=x(u,"&")[0];return new l.n.s(q,i.zb,q,"(organic)","organic",u,q)}}}};k.ba=function(p,u,m){var r=n(p,u+"=","&"),i=!s(r)?
l.J(r):(!s(m)?m:"-");return i};k.Nc=function(p){var u=k.o.ea,m=false,r,i;if(p&&"organic"==p.da){r=w(l.J(p.R));for(i=0;i<u[g];i++)m=m||w(u[i])==r}return m};k.Ec=function(){var p="",u="",m=k.Rb;if(z(m)||k.Ib(m))return;p=w(x(m,"://")[1]);if(f(p,"/")){u=l.F(p,l.w(p,"/"));if(f(u,"?"))u=x(u,"?")[0];p=x(p,"/")[0]}if(0==l.w(p,"www."))p=l.F(p,4);return new l.n.s(q,p,q,"(referral)","referral",q,u)};k.sc=function(p){var u="";if(k.o.pa){u=l.Db(p);u=""!=u?u+"&":u}u+=p.search;return u};k.zc=function(){return new l.n.s(q,
"(direct)",q,"(direct)","(none)",q,q)};k.Oc=function(p){var u=false,m,r,i=k.o.ga;if(p&&"referral"==p.da){m=w(l.d(p.ia));for(r=0;r<i[g];r++)u=u||f(m,w(i[r]))}return u};k.U=function(p){return q!=p&&p.Fa()};k.yc=function(p,u){var m="",r="-",i,b,e=0,j,t,v=k.f;if(!p)return"";t=k.a[l.m]?k.a[l.m]:"";m=k.sc(k.a.location);if(k.o.I&&p.Jb()){r=p.Ca();if(!s(r)&&!f(r,";")){p.Ra();return""}}r=n(t,l.X+v+".",";");i=k.Fc(m);if(k.U(i)){b=n(m,k.o.hb+"=","&");if("1"==b&&!s(r))return""}if(!k.U(i)){i=k.Fb();if(!s(r)&&
k.Nc(i))return""}if(!k.U(i)&&u){i=k.Ec();if(!s(r)&&k.Oc(i))return""}if(!k.U(i))if(s(r)&&u)i=k.zc();if(!k.U(i))return"";if(!s(r)){var y=x(r,"."),E=new l.n.s;E.Cb(y.slice(4).join("."));j=w(E.ka())==w(i.ka());e=y[3]*1}if(!j||u){var F=n(t,l.r+v+".",";"),I=F.lastIndexOf("."),G=I>9?l.F(F,I+1)*1:0;e++;G=0==G?1:G;p.Xb([v,k.ja,G,e,i.ka()].join("."));p.Ra();return"&utmcn=1"}else return"&utmcr=1"}};_gat.n.s=function(d,a,c,h,o,k,l){var s=this;s.v=d;s.ia=a;s.ra=c;s.L=h;s.da=o;s.R=k;s.vb=l};_gat.n.s.prototype.ka=
function(){var d=this,a=_gat,c=[],h=[[a.Wa,d.v],[a.Ya,d.ia],[a.$a,d.ra],[a.Ua,d.L],[a.Xa,d.da],[a.Za,d.R],[a.Va,d.vb]],o,k;if(d.Fa())for(o=0;o<h[a.c];o++)if(!a.q(h[o][1])){k=h[o][1].split("+").join("%20");k=k.split(" ").join("%20");a.h(c,h[o][0]+k)}return c.join("|")};_gat.n.s.prototype.Fa=function(){var d=this,a=_gat.q;return!(a(d.v)&&a(d.ia)&&a(d.ra))};_gat.n.s.prototype.Cb=function(d){var a=this,c=_gat,h=function(o){return c.J(c.C(d,o,"|"))};a.v=h(c.Wa);a.ia=h(c.Ya);a.ra=h(c.$a);a.L=h(c.Ua);a.da=
h(c.Xa);a.R=h(c.Za);a.vb=h(c.Va)};_gat.Z=function(){var d=this,a=_gat,c={},h="k",o="v",k=[h,o],l="(",s=")",q="*",f="!",n="'",w={};w[n]="'0";w[s]="'1";w[q]="'2";w[f]="'3";var x=1;function g(m,r,i,b){if(a.b==c[m])c[m]={};if(a.b==c[m][r])c[m][r]=[];c[m][r][i]=b}function z(m,r,i){return a.b!=c[m]&&a.b!=c[m][r]?c[m][r][i]:a.b}function B(m,r){if(a.b!=c[m]&&a.b!=c[m][r]){c[m][r]=a.b;var i=true,b;for(b=0;b<k[a.c];b++)if(a.b!=c[m][k[b]]){i=false;break}if(i)c[m]=a.b}}function A(m){var r="",i=false,b,e;for(b=0;b<k[a.c];b++){e=m[k[b]];if(a.b!=
e){if(i)r+=k[b];r+=p(e);i=false}else i=true}return r}function p(m){var r=[],i,b;for(b=0;b<m[a.c];b++)if(a.b!=m[b]){i="";if(b!=x&&a.b==m[b-1]){i+=b.toString();i+=f}i+=u(m[b]);a.h(r,i)}return l+r.join(q)+s}function u(m){var r="",i,b,e;for(i=0;i<m[a.c];i++){b=m.charAt(i);e=w[b];r+=a.b!=e?e:b}return r}d.Kc=function(m){return a.b!=c[m]};d.N=function(){var m=[],r;for(r in c)if(a.b!=c[r])a.h(m,r.toString()+A(c[r]));return m.join("")};d.Sc=function(m){if(m==a.b)return d.N();var r=[m.N()],i;for(i in c)if(a.b!=
c[i]&&!m.Kc(i))a.h(r,i.toString()+A(c[i]));return r.join("")};d._setKey=function(m,r,i){if(typeof i!="string")return false;g(m,h,r,i);return true};d._setValue=function(m,r,i){if(typeof i!="number"&&(a.b==Number||!(i instanceof Number)))return false;if(Math.round(i)!=i||i==NaN||i==Infinity)return false;g(m,o,r,i.toString());return true};d._getKey=function(m,r){return z(m,h,r)};d._getValue=function(m,r){return z(m,o,r)};d._clearKey=function(m){B(m,h)};d._clearValue=function(m){B(m,o)}};_gat.ic=function(d,a){var c=this;c.jd=a;c.Pc=d;c._trackEvent=function(h,o,k){return a._trackEvent(c.Pc,h,o,k)}};_gat.kc=function(d){var a=this,c=_gat,h=c.b,o=c.q,k=c.w,l=c.F,s=c.C,q=c.P,f=c.z,n="location",w=c.c,x=h,g=new c.hc,z=false;a.a=document;a.e=window;a.ja=Math.round((new Date).getTime()/1000);a.H=d;a.yb=a.a.referrer;a.va=h;a.j=h;a.A=h;a.M=false;a.aa=h;a.rb="";a.l=h;a.Ab=h;a.f=h;a.u=h;function B(){if("auto"==g.g){var b=a.a.domain;if("www."==l(b,0,4))b=l(b,4);g.g=b}g.g=c.T(g.g)}function A(){var b=g.g,e=k(b,"www.google.")*k(b,".google.")*k(b,"google.");return e||"/"!=g.p||k(b,"google.org")>-1}function p(b,
e,j){if(o(b)||o(e)||o(j))return"-";var t=s(b,c.r+a.f+".",e),v;if(!o(t)){v=f(t,".");v[5]=v[5]?v[5]*1+1:1;v[3]=v[4];v[4]=j;t=v.join(".")}return t}function u(){return"file:"!=a.a[n].protocol&&A()}function m(b){if(!b||""==b)return"";while(c.Lb(b.charAt(0)))b=l(b,1);while(c.Lb(b.charAt(b[w]-1)))b=l(b,0,b[w]-1);return b}function r(b,e,j){if(!o(b())){e(c.J(b()));if(!q(b(),";"))j()}}function i(b){var e,j=""!=b&&a.a[n].host!=b;if(j)for(e=0;e<g.B[w];e++)j=j&&k(c.T(b),c.T(g.B[e]))==-1;return j}a.Bc=function(){if(!g.g||
""==g.g||"none"==g.g){g.g="";return 1}B();return g.pb?c.t(g.g):1};a.tc=function(b,e){if(o(b))b="-";else{e+=g.p&&"/"!=g.p?g.p:"";var j=k(b,e);b=j>=0&&j<=8?"0":("["==b.charAt(0)&&"]"==b.charAt(b[w]-1)?"-":b)}return b};a.Ia=function(b){var e="",j=a.a;e+=a.aa?a.aa.Xc():"";e+=g.qa?a.rb:"";e+=g.ta&&!o(j.title)?"&utmdt="+c.d(j.title):"";e+="&utmhid="+c.uc()+"&utmr="+a.va+"&utmp="+a.Tc(b);return e};a.Tc=function(b){var e=a.a[n];b=h!=b&&""!=b?c.d(b,true):c.d(e.pathname+unescape(e.search),true);return b};a.$c=
function(b){if(a.Q()){var e="";if(a.l!=h&&a.l.N().length>0)e+="&utme="+c.d(a.l.N());e+=a.Ia(b);x.O(e,a.H,a.a,a.f)}};a.qc=function(){var b=new c.Y(a.a,g);return b.Ha(a.f)?b.Wc():h};a._getLinkerUrl=function(b,e){var j=f(b,"#"),t=b,v=a.qc();if(v)if(e&&1>=j[w])t+="#"+v;else if(!e||1>=j[w])if(1>=j[w])t+=(q(b,"?")?"&":"?")+v;else t=j[0]+(q(b,"?")?"&":"?")+v+"#"+j[1];return t};a.Zb=function(){var b;if(a.A&&a.A[w]>=10&&!q(a.A,"=")){a.u.Uc(a.A);a.u.cd();c._gasoDomain=g.g;c._gasoCPath=g.p;b=a.a.createElement("script");
b.type="text/javascript";b.id="_gasojs";b.src="https://www.google.com/analytics/reporting/overlay_js?gaso="+a.A+"&"+c.wa();a.a.getElementsByTagName("head")[0].appendChild(b)}};a.Jc=function(){var b=a.a[c.m],e=a.ja,j=a.u,t=a.f+"",v=a.e,y=v?v.gaGlobal:h,E,F=q(b,c.r+t+"."),I=q(b,c.W+t),G=q(b,c.ma+t),C,D=[],H="",K=false,J;b=o(b)?"":b;if(g.I){E=c.Db(a.a[n]);if(g.pa&&!o(E))H=E+"&";H+=a.a[n].search;if(!o(H)&&q(H,c.r)){j.Rc(H);if(!j.Jb())j.pc();C=j.ya()}r(j.Ba,j.Wb,j.fc);r(j.Aa,j.Na,j.Qa)}if(!o(C))if(o(j.K())||
o(j.za())){C=p(H,"&",e);a.M=true}else{D=f(j.K(),".");t=D[0]}else if(F)if(!I||!G){C=p(b,";",e);a.M=true}else{C=s(b,c.r+t+".",";");D=f(s(b,c.W+t,";"),".")}else{C=[t,c.Gc(),e,e,e,1].join(".");a.M=true;K=true}C=f(C,".");if(v&&y&&y.dh==t){C[4]=y.sid?y.sid:C[4];if(K){C[3]=y.sid?y.sid:C[4];if(y.vid){J=f(y.vid,".");C[1]=J[0];C[2]=J[1]}}}j.Ub(C.join("."));D[0]=t;D[1]=D[1]?D[1]:0;D[2]=undefined!=D[2]?D[2]:g.Yc;D[3]=D[3]?D[3]:C[4];j.La(D.join("."));j.Vb(t);if(!o(j.Hc()))j.Ma(j.t());j.dc();j.Pa();j.ec()};a.Lc=
function(){x=new c.jc(g)};a._initData=function(){var b;if(!z){a.Lc();a.f=a.Bc();a.u=new c.Y(a.a,g)}if(u())a.Jc();if(!z){if(u()){a.va=a.tc(a.Ac(),a.a.domain);if(g.sa){a.aa=new c.gc(g.ua);a.aa.xc()}if(g.qa){b=new c.n(a.f,a.a,a.va,a.ja,g);a.rb=b.yc(a.u,a.M)}}a.l=new c.Z;a.Ab=new c.Z;z=true}if(!c.Hb)a.Mc()};a._visitCode=function(){a._initData();var b=s(a.a[c.m],c.r+a.f+".",";"),e=f(b,".");return e[w]<4?"":e[1]};a._cookiePathCopy=function(b){a._initData();if(a.u)a.u.bd(a.f,b)};a.Mc=function(){var b=a.a[n].hash,
e;e=b&&""!=b&&0==k(b,"#gaso=")?s(b,"gaso=","&"):s(a.a[c.m],c.Sa,";");if(e[w]>=10){a.A=e;if(a.e.addEventListener)a.e.addEventListener("load",a.Zb,false);else a.e.attachEvent("onload",a.Zb)}c.Hb=true};a.Q=function(){return a._visitCode()%10000<g.ha*100};a.Vc=function(){var b,e,j=a.a.links;if(!g.Kb){var t=a.a.domain;if("www."==l(t,0,4))t=l(t,4);g.B.push("."+t)}for(b=0;b<j[w]&&(g.Ga==-1||b<g.Ga);b++){e=j[b];if(i(e.host))if(!e.gatcOnclick){e.gatcOnclick=e.onclick?e.onclick:a.Qc;e.onclick=function(v){var y=
!this.target||this.target=="_self"||this.target=="_top"||this.target=="_parent";y=y&&!a.oc(v);a.ad(v,this,y);return y?false:(this.gatcOnclick?this.gatcOnclick(v):true)}}}};a.Qc=function(){};a._trackPageview=function(b){if(u()){a._initData();if(g.B)a.Vc();a.$c(b);a.M=false}};a._trackTrans=function(){var b=a.f,e=[],j,t,v,y;a._initData();if(a.j&&a.Q()){for(j=0;j<a.j.la[w];j++){t=a.j.la[j];c.h(e,t.S());for(v=0;v<t.ca[w];v++)c.h(e,t.ca[v].S())}for(y=0;y<e[w];y++)x.O(e[y],a.H,a.a,b,true)}};a._setTrans=
function(){var b=a.a,e,j,t,v,y=b.getElementById?b.getElementById("utmtrans"):(b.utmform&&b.utmform.utmtrans?b.utmform.utmtrans:h);a._initData();if(y&&y.value){a.j=new c.i;v=f(y.value,"UTM:");g.G=!g.G||""==g.G?"|":g.G;for(e=0;e<v[w];e++){v[e]=m(v[e]);j=f(v[e],g.G);for(t=0;t<j[w];t++)j[t]=m(j[t]);if("T"==j[0])a._addTrans(j[1],j[2],j[3],j[4],j[5],j[6],j[7],j[8]);else if("I"==j[0])a._addItem(j[1],j[2],j[3],j[4],j[5],j[6])}}};a._addTrans=function(b,e,j,t,v,y,E,F){a.j=a.j?a.j:new c.i;return a.j.nb(b,e,
j,t,v,y,E,F)};a._addItem=function(b,e,j,t,v,y){var E;a.j=a.j?a.j:new c.i;E=a.j.xa(b);if(!E)E=a._addTrans(b,"","","","","","","");E.mb(e,j,t,v,y)};a._setVar=function(b){if(b&&""!=b&&A()){a._initData();var e=new c.Y(a.a,g),j=a.f;e.Na(j+"."+c.d(b));e.Qa();if(a.Q())x.O("&utmt=var",a.H,a.a,a.f)}};a._link=function(b,e){if(g.I&&b){a._initData();a.a[n].href=a._getLinkerUrl(b,e)}};a._linkByPost=function(b,e){if(g.I&&b&&b.action){a._initData();b.action=a._getLinkerUrl(b.action,e)}};a._setXKey=function(b,e,
j){a.l._setKey(b,e,j)};a._setXValue=function(b,e,j){a.l._setValue(b,e,j)};a._getXKey=function(b,e){return a.l._getKey(b,e)};a._getXValue=function(b,e){return a.l.getValue(b,e)};a._clearXKey=function(b){a.l._clearKey(b)};a._clearXValue=function(b){a.l._clearValue(b)};a._createXObj=function(){a._initData();return new c.Z};a._sendXEvent=function(b){var e="";a._initData();if(a.Q()){e+="&utmt=event&utme="+c.d(a.l.Sc(b))+a.Ia();x.O(e,a.H,a.a,a.f,false,true)}};a._createEventTracker=function(b){a._initData();
return new c.ic(b,a)};a._trackEvent=function(b,e,j,t){var v=true,y=a.Ab;if(h!=b&&h!=e&&""!=b&&""!=e){y._clearKey(5);y._clearValue(5);v=y._setKey(5,1,b)?v:false;v=y._setKey(5,2,e)?v:false;v=h==j||y._setKey(5,3,j)?v:false;v=h==t||y._setValue(5,1,t)?v:false;if(v)a._sendXEvent(y)}else v=false;return v};a.ad=function(b,e,j){a._initData();if(a.Q()){var t=new c.Z;t._setKey(6,1,e.href);var v=j?function(){a.rc(b,e)}:undefined;x.O("&utmt=event&utme="+c.d(t.N())+a.Ia(),a.H,a.a,a.f,false,true,v)}};a.rc=function(b,
e){if(!b)b=a.e.event;var j=true;if(e.gatcOnclick)j=e.gatcOnclick(b);if(j||typeof j=="undefined")if(!e.target||e.target=="_self")a.e.location=e.href;else if(e.target=="_top")a.e.top.document.location=e.href;else if(e.target=="_parent")a.e.parent.document.location=e.href};a.oc=function(b){if(!b)b=a.e.event;var e=b.shiftKey||b.ctrlKey||b.altKey;if(!e)if(b.modifiers&&a.e.Event)e=b.modifiers&a.e.Event.CONTROL_MASK||b.modifiers&a.e.Event.SHIFT_MASK||b.modifiers&a.e.Event.ALT_MASK;return e};a._setDomainName=
function(b){g.g=b};a.dd=function(){return g.g};a._addOrganic=function(b,e){c.h(g.fa,new c.cb(b,e))};a._clearOrganic=function(){g.fa=[]};a.hd=function(){return g.fa};a._addIgnoredOrganic=function(b){c.h(g.ea,b)};a._clearIgnoredOrganic=function(){g.ea=[]};a.ed=function(){return g.ea};a._addIgnoredRef=function(b){c.h(g.ga,b)};a._clearIgnoredRef=function(){g.ga=[]};a.fd=function(){return g.ga};a._setAllowHash=function(b){g.pb=b?1:0};a._setCampaignTrack=function(b){g.qa=b?1:0};a._setClientInfo=function(b){g.sa=
b?1:0};a._getClientInfo=function(){return g.sa};a._setCookiePath=function(b){g.p=b};a._setTransactionDelim=function(b){g.G=b};a._setCookieTimeout=function(b){g.wb=b};a._setDetectFlash=function(b){g.ua=b?1:0};a._getDetectFlash=function(){return g.ua};a._setDetectTitle=function(b){g.ta=b?1:0};a._getDetectTitle=function(){return g.ta};a._setLocalGifPath=function(b){g.Da=b};a._getLocalGifPath=function(){return g.Da};a._setLocalServerMode=function(){g.D=0};a._setRemoteServerMode=function(){g.D=1};a._setLocalRemoteServerMode=
function(){g.D=2};a.gd=function(){return g.D};a._getServiceMode=function(){return g.D};a._setSampleRate=function(b){g.ha=b};a._setSessionTimeout=function(b){g.Tb=b};a._setAllowLinker=function(b){g.I=b?1:0};a._setAllowAnchor=function(b){g.pa=b?1:0};a._setCampNameKey=function(b){g.db=b};a._setCampContentKey=function(b){g.eb=b};a._setCampIdKey=function(b){g.fb=b};a._setCampMediumKey=function(b){g.gb=b};a._setCampNOKey=function(b){g.hb=b};a._setCampSourceKey=function(b){g.ib=b};a._setCampTermKey=function(b){g.jb=
b};a._setCampCIdKey=function(b){g.kb=b};a._getAccount=function(){return a.H};a._getVersion=function(){return _gat.lb};a.kd=function(b){g.B=[];if(b)g.B=b};a.md=function(b){g.Kb=b};a.ld=function(b){g.Ga=b};a._setReferrerOverride=function(b){a.yb=b};a.Ac=function(){return a.yb}};_gat._getTracker=function(d){var a=new _gat.kc(d);return a};


