/**
 * _c and _d are for debugging purposes
 */ 

var _d = (function() {
    return {
        enabled : (!!~window.name.indexOf("debug")),
        
        enable : function() {
            window.name += "%debug%";
        }
    }
})();

var _c = (function() {
    return {
        log : function(sMsg) {
            if (_d.enabled && window.console && console.log) {
                console.log(sMsg);
            }
        },

        info : function(sMsg) {
            if (_d.enabled && window.console && console.info) {
                console.info(sMsg);
            }
        },
        
        dir : function(obj)  {
            if (_d.enabled && window.console && console.dir) {
                console.dir(obj);
            }
            else if (_d.enabled && window.console && console.log) {
                for (var xI in obj) {
                    console.log(xI +": "+ obj[xI]);
                }
            }
        },
        
        warn : function(sMsg) {
          if (_d.enabled && window.console) {
              if (console.warn) {
                  console.warn(sMsg);
              }
              else {
                  console.log("Warning: "+ sMsg);
              }
          }  
        },
        
        error : function(sMsg) {
            throw new Error(sMsg);        
        },
        
        time : function(sId) {
            if (_d.enabled && window.console && console.time) {
                console.time(sId);
            }
            else {
                _c.log("blaa");
            }
        },

        timeEnd : function(sId) {
            if (_d.enabled && window.console && console.timeEnd) {
                var toTimeEnd = setTimeout(function() {
                    console.timeEnd(sId);
                },1,sId);
            }
        },
        
        group : function(sName) {
            if (_d.enabled && window.console && console.groupCollapsed) {
                console.groupCollapsed(sName);
            }
            else if (_d.enabled && window.console && console.group) {
                console.group(sName);
            }
            else {
                return false;
            }
        },
        
        groupEnd : function(sName) {
            if (_d.enabled && window.console && console.groupEnd) {
                console.groupEnd(sName);
            }
            else {
                return false;
            }
        }
        
    }
})();


/**
 * @constructor Modal
 * @param
 *  {jQuery Object} modalWin
 *  {jQuery Object} dimmer
 *  {jQuery Object} modalBox
 *  {String} [content]
 * 
 * @return {Object} Modal
 * 
 */

var Modal = function(param) {
    var _modalId = param['modalId'];
    var _modalClass = param['modalClass'];
    var _modalWin = param['modalWin'] || jQuery('<div class="modal-window"></div>');
    var _dimmer = param['dimmer'] || (param['noDimmer'] ? false : jQuery('<div class="dimmer"></div>'));
    var _dimmerClass = param['dimmerClass'];
    var _modalBox = param['modalBox'] || jQuery('<div class="box"></div>');
    var _close = param['closeButton'] || (param['noClose'] ? false : jQuery("<a class='close'>Sulje</a>"));
    var _contentContainer = jQuery('<div class="content"></div>');
    var _content = param['content'];
    var _header = jQuery('<div class="header">' + (param['header'] || '') + '</div>');
    var _initialState = param['initialState'] || '';
    var _onClose = param['onClose'];
    var _state = '';
    
    // Private Function Declarations
    var _resetProperties;
    
    _resetProperties = function() {
        if (_modalWin) {
            _modalWin.remove();
        }
        _modalWin = null;
        _modalBox = null;
    };
    
    this.show = function(callback) {
        var self = this;
        
        if (_modalWin === undefined || _modalBox === undefined) {
            _c.warn("Modal parameters are incorrectly specified.");
            return false;
        }

        _modalId && _modalWin.attr('id', _modalId);
        _modalClass && _modalWin.addClass(_modalClass);
        _modalWin.appendTo(document.body);
        _dimmer && _dimmer.appendTo(_modalWin) && _dimmerClass && _dimmer.addClass(_dimmerClass);
        _close && _close.appendTo(_header);
        _header.appendTo(_modalBox);
        _contentContainer.appendTo(_modalBox);
        _modalBox.appendTo(_modalWin).hide();
        
        var closehandler = function(evt) {
            evt.preventDefault();
            self.close.call(self);
        };

        _modalBox.delegate(".close", "click", closehandler);
        
        if (_close) {
            if (_dimmer) {
                _dimmer.click(closehandler);
            } else {
                jQuery("body").live("click.modelessClick", function(evt) { evt.preventDefault(); self.close.call(self);});
            }
        }
        
        self.changeState(_initialState, _content, callback);
        _dimmer && _dimmer.hide().fadeIn(250);
    }
    
    this.adjustModalPosition = function(animate){
        var height = _modalBox.outerHeight();
        var win = jQuery(window);
        
        if (height < win.height()) {
            if (animate && _modalBox.css('top') == '50%') {
                _modalBox.animate({marginTop: (0 - (height / 2))}, 250);
                return;
            }
            
            _modalBox.css({
                marginTop: win.scrollTop() + (0 - (height / 2)) + 'px',
                top: '50%'
            });
            
            return;
        }
        
        _modalBox.css({
            marginTop: '100px',
            top: 0
        });
    };

    this.close = function(){
        this.changeState('unload', null, function(){
            jQuery("body").die("click.modelessClick");
            
            if (_dimmer) { 
                _dimmer.fadeOut(250, function(){
                    _resetProperties();
                    _dimmer = null;
                });
            }
            else {
                _resetProperties();
            }
        });
        
        if (typeof _onClose == 'function') {
            _onClose();
        }
    };
        
    this.changeState = function(state, content, callback){
        var self = this;
        var old = _state;
        _state = state;
        
        _modalBox.fadeOut(250, function(){
            if (!_modalBox) {
                return false;
            }
            
            old && _modalBox.removeClass(old);
            state && _modalBox.addClass(state);
            
            if (content) {
                _contentContainer.html(content);
                self.adjustModalPosition();
                _modalBox.fadeIn(250);
            } else {
                _contentContainer.empty();
            }
            
            if (typeof callback == 'function') {
                callback();
            }
        });
    };
    
    this.getBox = function(){
        return _modalBox;
    };
    
    this.getContent = function(){
        return _contentContainer;
    };
    
    this.getState = function(){
        return _state;
    };

    return this;
};


/**
 * @class SiteCatalystEvents
 * For creating dynamic events for Site Catalyst
 *
 */
var SiteCatalystEvents;

jQuery(document).ready( function() {
    SiteCatalystEvents = ( function($) {
        var _events = [],
        self = {};

        if (!window.s) {
            return {
                "dispatch" : function() {
                },
                "pushEvents" : function() {
                },
                "sendEvents" : function() {
                },
                "setProp" : function() {
                },
                "setTotalAmount" : function() {
                    
                }
            };
        }

        s.events = ""; // [CUSTOM_EVENTS]
        s.products = ""; // [PRODUCT_INFORMATION]
        s.prop1 = $("#header-search-what").val(); // [SEARCH_TERM]
        s.prop2 = ""; // [SEARCH_TYPE]
        s.prop3 = 0; // [SEARCH_RESULTS]
        s.prop4 = ""; // NOT_USED_ANYWHERE
        s.prop7 = ""; // [ROUTE_FROM]
        s.prop8 = ""; // [ROUTE_TO]
        s.prop9 = ""; // [MAIN_CATEGORY]
        s.prop13 = $("#header-search-where").val(); // [LOCATION]
        s.prop16 = ""; // [DOMINANT_CATEGORY]
        s.prop17 = ""; // [SEARCH_QUERY_EXPANSION_USED]
        s.prop25 = ""; // [FOR ROI REPORTING SYSTEM]

        /**
         * Private function declarations
         */
        var _generateProducts,
        _initLinkTracking,
        _resetProperties,
        _resolveLinkMbsId,
        _sendEvents;

        _generateProducts = function(startIndex) {
            s.products = "";

            var iI = 0, iL = _events.length;

            if (!!startIndex) {
                for (;iI<iL;iI++) {
                    s.products += ";yp:"+ _events[iI] +";;;event4="+ (startIndex + iI) +",";
                }
                
                s.products = s.products.slice(0,-1); // Removes the last comma
            }

        };
        
        _initAlcesLinkTracking = function() {
            _c.info("initAlcesLinkTracking");
            $('a.www').live("mousedown", function() {
                if (s) {
                    var mbs_id = (Alces && Alces.ypProfile) ? Alces.ypProfile.id : _resolveLinkMbsId(this); 
                    s.linkTrackVars = 'prop9,eVar9,eVar25,prop27,eVar27,prop28,eVar28,prop47,products,events';
                    s.linkTrackEvents = 'event5,event13';
                    s.events = 'event5,event13';
                    s.prop9 = s.pageName;
                    s.prop27 = this.href;
                    s.prop28 = (Alces && Alces.ypProfile) ? Alces.ypProfile.category : "unavailable";
                    s.prop47 = 'click website';
                    s.products = ';yp:' + mbs_id + ';;;event13=1;eVar25=click website';
                    _c.log("tracking link with: "+ s.products);
                    s.tl(this, 'o', this.href);
                }
            });

            $('a.tactical-ad-link').live("mousedown", function() {
                if (s) {
                    var mbs_id = (Alces && Alces.ypProfile) ? Alces.ypProfile.id : _resolveLinkMbsId(this); 
                    s.linkTrackVars = 'prop9,eVar9,prop11,eVar11,eVar25,prop28,eVar28,prop47,products,events';
                    s.linkTrackEvents = 'event7,event13,';
                    s.events = 'event7,event13';
                    s.prop9 = s.pageName;
                    s.prop11 = this.href;
                    s.prop28 = (Alces && Alces.ypProfile) ? Alces.ypProfile.category : "unavailable";
                    s.prop47 = 'click ad';
                    s.products = ';yp:' + mbs_id + ';;;event13=1;eVar25=click ad';
                    _c.log("tracking tactical ad with: "+ s.products);
                    s.tl(this, 'o', this.href);
                }
            });

            $('a.email-link').live("mousedown", function(){
                if (s) {
                    var mbs_id = (Alces && Alces.ypProfile) ? Alces.ypProfile.id : _resolveLinkMbsId(this); 
                    s.linkTrackVars = 'prop9,eVar9,eVar25,prop28,eVar28,prop29,eVar29,prop47,products,events';
                    s.linkTrackEvents = 'event13,event29,';
                    s.events = 'event13,event29';
                    s.prop9 = s.pageName;
                    s.prop28 = (Alces && Alces.ypProfile) ? Alces.ypProfile.category : "unavailable";
                    s.prop29 = this.href;
                    s.prop47 = 'click email';
                    s.products = ';yp:' + mbs_id + ';;;event13=1;eVar25=click email';
                    _c.log("tracking email link with: "+ s.products);
                    s.tl(this, 'o', this.href);
                }
            });

            $("#send-wp-contact-modal input[type=submit]").live("mousedown", function() {
                if (s && $("#txt-send-contact-to").val().length) {
                    var mbs_id = (Alces && Alces.ypProfile) ? Alces.ypProfile.id : _resolveLinkMbsId(this); 
                    s.linkTrackVars='prop9,eVar9,eVar25,prop28,eVar28,prop47,products,events';
                    s.linkTrackEvents='event19,event13';
                    s.events='event19,event13';
                    s.prop9=s.pageName;
                    s.prop28 = (Alces && Alces.ypProfile) ? Alces.ypProfile.category : "unavailable";
                    s.prop47='send to mobile';
                    s.products = ';yp:' + mbs_id + ';;;event13=1;eVar25=send to mobile';
                    _c.log("tracking send to mobile with: "+ s.products);
                    s.tl(true,'o',"send_to_mobile");
                }
            });
        };
        
        _resetProperties = function() {
            _events = [];
            self.setProp("events","");
            self.setProp("products","");
            self.setProp("prop1", "");
            self.setProp("prop2","ms");
            self.setProp("prop3","");
            self.setProp("prop4","");
            self.setProp("prop7","");
            self.setProp("prop8","");
            self.setProp("prop9","");
            self.setProp("prop13","");
            self.setProp("prop16","");
            self.setProp("prop25","");
            self.setProp("prop47","");
        };

        _resolveLinkMbsId = function(link){
            var mbs_id = '';

            jQuery.each(link.className.split(' '), function(key, val){
                var pos = val.indexOf('mbsid-');

                if (pos > -1) {
                    mbs_id = jQuery.trim(val.substring(pos + 6));
                    return false;
                }
            });
            
            return mbs_id;
        };
        
        _sendEvents = function(isRouting, isPopup) {
            _c.info("SiteCatalystEvents :: _sendEvents()");
            
            if (isRouting && self.getProp("prop7").length && self.getProp("prop8").length) {
                _c.info("Sending SC info with Routing Info.");
            } else if (isPopup && self.getProp("prop9").length) {
                _c.info("Sending SC Popup info with s.products: "+ s.products);
            } else if (s.products.length) {
                _c.info("Sending SC info with s.products: "+ s.products);
            } else {
                _c.warn("No SC s.products sent.");
            }

            // Send data
            var s_code = s.t();

            if (s_code) {
                document.write(s_code);
            }

            _resetProperties();

            return true;
        };
        /**
         * @function dispatch
         * Dispatches events to the server
         *
         * @return {Boolean} success
         */
        self.dispatch = function(startIndex, isRouting, isPopup) {
            if (isRouting) {
                _sendEvents(isRouting, isPopup);
            } else if (isPopup) {
                self.sendExtendedPopup();

            } else {
                var start = startIndex || 0;
                
                _generateProducts(start);

                var success = _sendEvents();

                if (success) {
                    _c.info("Events dispatched to Site Catalyst.");
                } else {
                    _c.warn("No events to dispatch.");
                }

                return success;
            }
        };
        /**
         * @function pushEvents
         * @param {Array} events
         *
         * @return {Boolean} success
         */
        self.pushEvents = function(events) {
            var iI=0,iL=events.length;

            for (;iI<iL;iI++) {
                _events.push(events[iI]);
            }

            return !!events.length;
        };
        
        // This is completely outiside of normal behavior of SiteCatalyst
        self.sendExitLink = function() {
            if(!s) {
                return true;
            }
            
            _resetProperties();

            s.linkTrackVars = 'prop9,eVar9,eVar25,prop27,eVar27,prop28,eVar28,prop47,products,events';
            s.linkTrackEvents = 'event5,event13';
            s.events = 'event5,event13';
            s.prop9 = "ms_business"; //s.pageName;
            s.prop27 = this.href;
            s.prop28 = jQuery(".popupHeader").data("main-category");
            s.prop47 = 'click website';
            s.products = ';yp:'+ jQuery(".popupHeader").data("id") +';;;event13=1;eVar25=click website';
            
            _c.info("SendExitLink: "+ this.href);
            s.tl(this,'o', this.href);
            
            _resetProperties();
        };
                
        self.sendRoutingFetchRoute = function (routeFrom, routeTo, visibleMapLayer, isLoggedIn, noResults) {
        // User makes a route search.             
            _c.log('SiteCatalystEvents.sendRoutingFetchRoute(' + routeFrom + ', ' + routeTo + ', ' + visibleMapLayer + ', ' + isLoggedIn + ')');
            
            SiteCatalystEvents.setProp("prop1","");
            SiteCatalystEvents.setProp("prop2","ro");
            SiteCatalystEvents.setProp("prop3", !!noResults ? "0" : "1");
            SiteCatalystEvents.setProp("prop7", routeFrom);
            SiteCatalystEvents.setProp("prop8", routeTo);
            SiteCatalystEvents.setProp("prop10", visibleMapLayer);
            SiteCatalystEvents.setProp("prop13", "");
            SiteCatalystEvents.setProp("prop16", "");
            SiteCatalystEvents.setProp("prop17","");
            SiteCatalystEvents.setProp("prop25","ms_route");
            SiteCatalystEvents.setProp("prop30", isLoggedIn);
            SiteCatalystEvents.setProp("pageName", "ms_route");
            SiteCatalystEvents.setProp("events", !!noResults ? "event8,event40" : "event8");
    
            SiteCatalystEvents.dispatch(0, true);
        };

        // This is completely outside of normal behavior of SiteCatalyst
        self.sendOfferLink = function() {
            if(!s) {
                return true;
            }

            _resetProperties();

            s.linkTrackVars='prop9,eVar9,prop11,eVar11,eVar25,prop28,eVar28,prop47,products,events';
            s.linkTrackEvents='event7,event13';
            s.events='event7,event13';

            s.prop9 = "ms_business"; //s.pageName;
            s.prop11=this.href;
            s.prop28 = jQuery(".popupHeader").data("main-category");;
            s.prop47='click ad';
            s.products=';yp:'+ jQuery(".popupHeader").data("id") +';;;event13=1;eVar25=click ad';

            _c.info("SendOfferLink: "+ this.href);
            s.tl(this,'o',this.href);
            
            _resetProperties();
        };
        
        self.sendExtendedPopup = function() {
            if (s) {
                _resetProperties(); 

                s.linkTrackVars = 'prop28,eVar28,products,events';
                s.linkTrackEvents = 'event27';
                s.prop28 = jQuery(".popupHeader").data("main-category");
                s.products=";yp:"+ jQuery(".popupHeader").data("id");
                s.events="event27";
                s.tl(true,'o','ms_extended_profile');

                _resetProperties();
            }
        };

        /**
         * Happens approx ~2500ms after viewing the popup.
         * We report to SC that user has actually viewed current company in popup
         */
        self.sendProfileViewedInPopup = function() {
            if (s) {
                _c.log("SiteCatalystEvents.sendProfileViewedInPopup");
                
                s.linkTrackVars = 'prop28,eVar28,products,events';
                s.linkTrackEvents = 'event26';
                s.prop28= jQuery(".popupHeader").data("main-category");
                s.products=";yp:"+ jQuery(".popupHeader").data("id");
                s.events="event26";
                s.tl(true,'o','ms_profile');
            }            
        }; 


        self.sendMapAddSimilarLocations = function (similarLocationsCount, visibleLayer, whereValue, islLoggedIn) {
            _c.log("SiteCatalystEvents.sendMapAddSimilarLocations");
            
            SiteCatalystEvents.setProp({
                "pageName": "ms_location_disambiguation",
                "channel": "ms",
                "prop2": "lo",
                "prop3": similarLocationsCount,
                "prop10": visibleLayer,
                "prop13": whereValue,
                "prop25": "ms_location",
                "prop30": isLoggedIn,
                "events": "event39"
            });
            SiteCatalystEvents.dispatch(0);            
        }


        
        self.sendMapShowResults = function(idsForSiteCatalyst, what, visibleLayer, where, isLoggedIn, startIndex) {
            _c.log("SiteCatalystEvents.sendMapShowResults ::  with " + idsForSiteCatalyst + " " + what + " " + visibleLayer + " " + where + " " + isLoggedIn + " " + startIndex);
            
            SiteCatalystEvents.pushEvents(idsForSiteCatalyst);            
            SiteCatalystEvents.setProp("pageName", "ms_business");
            SiteCatalystEvents.setProp("prop1", what);
            SiteCatalystEvents.setProp("prop2", "ms");
            // prop3 set in _paginateSidebar()
            SiteCatalystEvents.setProp("prop10", visibleLayer);
            SiteCatalystEvents.setProp("prop13", where);
            // prop16 set in populate()
            // prop17 set in appendData()
            SiteCatalystEvents.setProp("prop25", "ms_business_1");
            SiteCatalystEvents.setProp("prop30", isLoggedIn);
            
            SiteCatalystEvents.dispatch(startIndex);            
        };
        
        
        self.sendMapSearchNoResults = function() {
            _c.log("SiteCatalystEvents.sendMapSearchNoResults ::");
            
            SiteCatalystEvents.setProp("prop3", "0");
            SiteCatalystEvents.setProp("events", "event30,event40");
        };
        
        
        self.sendSingleVenue = function(noResults, visibleLayer, whereFieldValue, isLoggedIn) {
            _c.log("SiteCatalystEvents.sendSingleVenue :: with "+ ((noResults) ? "no" : "single") + " result.");
            
            SiteCatalystEvents.pushEvents(["-1"]);
            SiteCatalystEvents.setProp("products", "");
            SiteCatalystEvents.setProp("pageName", "ms_location");
            SiteCatalystEvents.setProp("channel", "ms");
            SiteCatalystEvents.setProp("prop2", "lo");
            SiteCatalystEvents.setProp("prop3", (noResults ? "0" : "1"));
            SiteCatalystEvents.setProp("prop10", visibleLayer);
            SiteCatalystEvents.setProp("prop13", whereFieldValue);
            SiteCatalystEvents.setProp("prop25", "ms_location");
            SiteCatalystEvents.setProp("prop30", isLoggedIn);
            SiteCatalystEvents.setProp("events", noResults ? "event30,event40" : "event30");
            SiteCatalystEvents.dispatch(0);            
        }

        
        self.getProp = function(prop) {
            if (prop) {
                return s[prop];
            }

            return false;
        };
        
        self.setProp = function(prop, value) {
            if (prop) {
                if (typeof prop === "string") {
                    s[prop] = value || "";
                }
                else if (typeof prop === "object") {
                    var xI;
                    for (xI in prop) {
                        s[xI] = prop[xI];
                    }
                }

                return true;
            }

            return false;
        };
                
        self.setTotalAmount = function(totalAmount) {
            /* 
               This functionality was for grouping amounts,
               currently we're using exact amount
               
            var amounts = [0,1,2,11,26,51,101,501];
            var amountsStr = ["0", "1", "1-10", "11-25", "26-50", "51-100", "101-500", "> 500"];
            var iL = amounts.length;

            while (iL--) {
                if (totalAmount >= amounts[iL]) {
                    totalAmount = amountsStr[iL];
                    break;
                }
            }
            */

            this.setProp("prop3", totalAmount);
        };
        
        var _init = (function() {
            _c.info("SiteCatalystEvents.init()");

            if (window.Alces && Alces.Core) {
                _initAlcesLinkTracking();
            }
            
        }());
        
        return self;
    }(jQuery));
});


//fgnass.github.com/spin.js
//(function(a,b,c){function O(a){H(arguments,function(b,d){a[b]===c&&(a[b]=d)});return a}function N(a){H(arguments,function(b,c){a[m][M(a,b)||b]=c});return a}function M(a,b){var d=a[m],f,g;if(d[b]!==c)return b;b=b.charAt(0).toUpperCase()+b.slice(1);for(g=0;g<E[e];g++){f=E[g]+b;if(d[f]!==c)return f}}function L(a,b){var c=[j,b,~~(a*100)].join("-"),d="{"+j+":"+a+"}",f;if(!F[c]){for(f=0;f<E[e];f++)try{K.insertRule("@"+(E[f]&&"-"+E[f].toLowerCase()+"-"||"")+"keyframes "+c+"{0%{"+j+":1}"+b+"%"+d+"to"+d+"}",K.cssRules[e])}catch(g){}F[c]=1}return c}function J(a,b,c){c&&!c[t]&&J(a,c),a.insertBefore(b,c||null);return a}function I(a){var c=b.createElement(a||"div");H(arguments,function(a,b){c[a]=b});return c}function H(a,b){var c=~~((a[e]-1)/2);for(var d=1;d<=c;d++)b(a[d*2-1],a[d*2])}var d="width",e="length",f="radius",g="lines",h="trail",i="color",j="opacity",k="speed",l="shadow",m="style",n="height",o="left",p="top",q="px",r="childNodes",s="firstChild",t="parentNode",u="position",v="relative",w="absolute",x="animation",y="transform",z="Origin",A="Timeout",B="coord",C="#000",D=m+"Sheets",E="webkit0Moz0ms0O".split(0),F={},G;J(b.getElementsByTagName("head")[0],I(m));var K=b[D][b[D][e]-1],P=function(a){this.opts=O(a||{},g,12,h,100,e,7,d,5,f,10,i,C,j,.25,k,1)},Q=P.prototype={spin:function(b){var c=this,d=c.el=c[g](c.opts);b&&J(b,N(d,o,~~(b.offsetWidth/2)+q,p,~~(b.offsetHeight/2)+q),b[s]);if(!G){var e=c.opts,f=0,i=20/e[k],l=(1-e[j])/(i*e[h]/100),m=i/e[g];(function n(){f++;for(var b=e[g];b;b--){var h=Math.max(1-(f+b*m)%i*l,e[j]);c[j](d,e[g]-b,h,e)}c[A]=c.el&&a["set"+A](n,50)})()}return c},stop:function(){var b=this,d=b.el;a["clear"+A](b[A]),d&&d[t]&&d[t].removeChild(d),b.el=c;return b}};Q[g]=function(a){function s(b,c){return N(I(),u,w,d,a[e]+a[d]+q,n,a[d]+q,"background",b,"boxShadow",c,y+z,o,y,"rotate("+~~(360/a[g]*m)+"deg) translate("+a[f]+q+",0)","borderRadius","100em")}var b=N(I(),u,v),c=L(a[j],a[h]),m=0,r;for(;m<a[g];m++)r=N(I(),u,w,p,1+~(a[d]/2)+q,y,"translate3d(0,0,0)",x,c+" "+1/a[k]+"s linear infinite "+(1/a[g]/a[k]*m-1/a[k])+"s"),a[l]&&J(r,N(s(C,"0 0 4px "+C),p,2+q)),J(b,J(r,s(a[i],"0 0 1px rgba(0,0,0,.1)")));return b},Q[j]=function(a,b,c){a[r][b][m][j]=c};var R="behavior",S="url(#default#VML)",T="group0roundrect0fill0stroke".split(0);(function(){var a=N(I(T[0]),R,S),b;if(!M(a,y)&&a.adj){for(b=0;b<T[e];b++)K.addRule(T[b],R+":"+S);Q[g]=function(){function s(c,e,l){J(k,J(N(h(),"rotation",360/a[g]*c+"deg",o,~~e),J(N(I(T[1],"arcsize",1),d,b,n,a[d],o,a[f],p,-a[d]/2,"filter",l),I(T[2],i,a[i],j,a[j]),I(T[3],j,0))))}function h(){return N(I(T[0],B+"size",c+" "+c,B+z,-b+" "+ -b),d,c,n,c)}var a=this.opts,b=a[e]+a[d],c=2*b,k=h(),m=~(a[e]+a[f]+a[d])+q,r;if(a[l])for(r=1;r<=a[g];r++)s(r,-2,"progid:DXImage"+y+".Microsoft.Blur(pixel"+f+"=2,make"+l+"=1,"+l+j+"=.3)");for(r=1;r<=a[g];r++)s(r);return J(N(I(),"margin",m+" 0 0 "+m,u,v),k)},Q[j]=function(a,b,c,d){d=d[l]&&d[g]||0,a[s][r][b+d][s][s][j]=c}}else G=M(a,x)})(),a.Spinner=P})(window,document);
//fgnass.github.com/spin.js#v1.2.2
(function(window, document, undefined) {

/**
 * Copyright (c) 2011 Felix Gnass [fgnass at neteye dot de]
 * Licensed under the MIT license
 */

  var prefixes = ['webkit', 'Moz', 'ms', 'O'], /* Vendor prefixes */
      animations = {}, /* Animation rules keyed by their name */
      useCssAnimations;

  /**
   * Utility function to create elements. If no tag name is given,
   * a DIV is created. Optionally properties can be passed.
   */
  function createEl(tag, prop) {
    var el = document.createElement(tag || 'div'),
        n;

    for(n in prop) {
      el[n] = prop[n];
    }
    return el;
  }

function isDescendant(parent, child) {
     var node = child.parentNode;
     while (node != null) {
         if (node == parent) {
             return true;
         }
         node = node.parentNode;
     }
     return false;
}

  /**
   * Inserts child1 before child2. If child2 is not specified,
   * child1 is appended. If child2 has no parentNode, child2 is
   * appended first.
   */
    function ins(parent, child1, child2) {
      if (child2) {
        if (!child2.parentNode) {
            ins(parent, child2);
        } else if (child2.parentNode && !isDescendant(parent, child2)){
            child2 = null;
        }    
      }
      parent.insertBefore(child1, child2||null);        
      return parent;
    }

  /**
   * Insert a new stylesheet to hold the @keyframe or VML rules.
   */
  var sheet = (function() {
    var el = createEl('style');
    ins(document.getElementsByTagName('head')[0], el);
    return el.sheet || el.styleSheet;
  })();

  /**
   * Creates an opacity keyframe animation rule and returns its name.
   * Since most mobile Webkits have timing issues with animation-delay,
   * we create separate rules for each line/segment.
   */
  function addAnimation(alpha, trail, i, lines) {
    var name = ['opacity', trail, ~~(alpha*100), i, lines].join('-'),
        start = 0.01 + i/lines*100,
        z = Math.max(1-(1-alpha)/trail*(100-start) , alpha),
        prefix = useCssAnimations.substring(0, useCssAnimations.indexOf('Animation')).toLowerCase(),
        pre = prefix && '-'+prefix+'-' || '';

    if (!animations[name]) {
      sheet.insertRule(
        '@' + pre + 'keyframes ' + name + '{' +
        '0%{opacity:'+z+'}' +
        start + '%{opacity:'+ alpha + '}' +
        (start+0.01) + '%{opacity:1}' +
        (start+trail)%100 + '%{opacity:'+ alpha + '}' +
        '100%{opacity:'+ z + '}' +
        '}', 0);
      animations[name] = 1;
    }
    return name;
  };

  /**
   * Tries various vendor prefixes and returns the first supported property.
   **/
  function vendor(el, prop) {
    var s = el.style,
        pp,
        i;

    if(s[prop] !== undefined) return prop;
    prop = prop.charAt(0).toUpperCase() + prop.slice(1);
    for(i=0; i<prefixes.length; i++) {
      pp = prefixes[i]+prop;
      if(s[pp] !== undefined) return pp;
    }
  }

  /**
   * Sets multiple style properties at once.
   */
  function css(el, prop) {
    for (var n in prop) {
      el.style[vendor(el, n)||n] = prop[n];
    }
    return el;
  }

  /**
   * Fills in default values.
   */
  function merge(obj) {
    for (var i=1; i < arguments.length; i++) {
      var def = arguments[i];
      for (var n in def) {
        if (obj[n] === undefined) obj[n] = def[n];
      }
    }
    return obj;
  }

  /**
   * Returns the absolute page-offset of the given element.
   */
  function pos(el) {
    var o = {x:el.offsetLeft, y:el.offsetTop};
    while((el = el.offsetParent)) {
      o.x+=el.offsetLeft;
      o.y+=el.offsetTop;
    }
    return o;
  }

  /** The constructor */
  var Spinner = function Spinner(o) {
    if (!this.spin) return new Spinner(o);
    this.opts = merge(o || {}, Spinner.defaults, defaults);
  },
  defaults = Spinner.defaults = {
    lines: 12, // The number of lines to draw
    length: 7, // The length of each line
    width: 5, // The line thickness
    radius: 10, // The radius of the inner circle
    color: '#000', // #rgb or #rrggbb
    speed: 1, // Rounds per second
    trail: 100, // Afterglow percentage
    opacity: 1/4,
    fps: 20
  },
  proto = Spinner.prototype = {
    spin: function(target) {
      this.stop();
      var self = this,
          el = self.el = css(createEl(), {position: 'relative'}),
          ep, // element position
          tp; // target position

      if (target) {
        tp = pos(ins(target, el, target.firstChild));
        ep = pos(el);
        css(el, {
          left: (target.offsetWidth >> 1) - ep.x+tp.x + 'px',
          top: (target.offsetHeight >> 1) - ep.y+tp.y + 'px'
        });
      }
      el.setAttribute('aria-role', 'progressbar');
      self.lines(el, self.opts);
      if (!useCssAnimations) {
        // No CSS animation support, use setTimeout() instead
        var o = self.opts,
            i = 0,
            fps = o.fps,
            f = fps/o.speed,
            ostep = (1-o.opacity)/(f*o.trail / 100),
            astep = f/o.lines;

        (function anim() {
          i++;
          for (var s=o.lines; s; s--) {
            var alpha = Math.max(1-(i+s*astep)%f * ostep, o.opacity);
            self.opacity(el, o.lines-s, alpha, o);
          }
          self.timeout = self.el && setTimeout(anim, ~~(1000/fps));
        })();
      }
      return self;
    },
    stop: function() {
      var el = this.el;
      if (el) {
        clearTimeout(this.timeout);
        if (el.parentNode) el.parentNode.removeChild(el);
        this.el = undefined;
      }
      return this;
    }
  };
  proto.lines = function(el, o) {
    var i = 0,
        seg;

    function fill(color, shadow) {
      return css(createEl(), {
        position: 'absolute',
        width: (o.length+o.width) + 'px',
        height: o.width + 'px',
        background: color,
        boxShadow: shadow,
        transformOrigin: 'left',
        transform: 'rotate(' + ~~(360/o.lines*i) + 'deg) translate(' + o.radius+'px' +',0)',
        borderRadius: (o.width>>1) + 'px'
      });
    }
    for (; i < o.lines; i++) {
      seg = css(createEl(), {
        position: 'absolute',
        top: 1+~(o.width/2) + 'px',
        transform: 'translate3d(0,0,0)',
        opacity: o.opacity,
        animation: useCssAnimations && addAnimation(o.opacity, o.trail, i, o.lines) + ' ' + 1/o.speed + 's linear infinite'
      });
      if (o.shadow) ins(seg, css(fill('#000', '0 0 4px ' + '#000'), {top: 2+'px'}));
      ins(el, ins(seg, fill(o.color, '0 0 1px rgba(0,0,0,.1)')));
    }
    return el;
  };
  proto.opacity = function(el, i, val) {
    if (i < el.childNodes.length) el.childNodes[i].style.opacity = val;
  };

  /////////////////////////////////////////////////////////////////////////
  // VML rendering for IE
  /////////////////////////////////////////////////////////////////////////

  /** 
   * Check and init VML support
   */
  (function() {
    var s = css(createEl('group'), {behavior: 'url(#default#VML)'}),
        i;

    if (!vendor(s, 'transform') && s.adj) {

      // VML support detected. Insert CSS rules ...
      for (i=4; i--;) sheet.addRule(['group', 'roundrect', 'fill', 'stroke'][i], 'behavior:url(#default#VML)');

      proto.lines = function(el, o) {
        var r = o.length+o.width,
            s = 2*r;

        function grp() {
          return css(createEl('group', {coordsize: s +' '+s, coordorigin: -r +' '+-r}), {width: s, height: s});
        }

        var g = grp(),
            margin = ~(o.length+o.radius+o.width)+'px',
            i;

        function seg(i, dx, filter) {
          ins(g,
            ins(css(grp(), {rotation: 360 / o.lines * i + 'deg', left: ~~dx}),
              ins(css(createEl('roundrect', {arcsize: 1}), {
                  width: r,
                  height: o.width,
                  left: o.radius,
                  top: -o.width>>1,
                  filter: filter
                }),
                createEl('fill', {color: o.color, opacity: 0.25}),
                createEl('stroke', {opacity: 0}) // transparent stroke to fix color bleeding upon opacity change
              )
            )
          );
        }

        if (o.shadow) {
          for (i = 1; i <= o.lines; i++) {
            seg(i, -2, 'progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)');
          }
        }
        for (i = 1; i <= o.lines; i++) {
          seg(i);
        }
        return ins(css(el, {
          margin: margin + ' 0 0 ' + margin,
          zoom: 1
        }), g);
      };
      proto.opacity = function(el, i, val, o) {
        var c = el.firstChild;
        o = o.shadow && o.lines || 0;
        if (c && i+o < c.childNodes.length) {
          c = c.childNodes[i+o]; c = c && c.firstChild; c = c && c.firstChild;
          if (c) c.opacity = val;
        }
      };
    }
    else {
      useCssAnimations = vendor(s, 'animation');
    }
  })();

  window.Spinner = Spinner;

})(window, document);

var LoadingIndicator = (function() {
    var self = {},
        $parent,
        _spinner;
    
    self.append = function(targetId) {
        var opts = {
            lines: 12,          // The number of lines to draw
            length: 7,          // The length of each line
            width: 4,           // The line thickness
            radius: 10,         // The radius of the inner circle
            color: '#FFFFFF',   // #rgb or #rrggbb
            speed: 1,           // Rounds per second
            trail: 75,          // Afterglow percentage
            shadow: true        // Whether to render a shadow
        };

        var target = document.getElementById(targetId);
        if (target) {
            $parent = jQuery(target).parent().fadeIn(320);
            _spinner = new Spinner(opts).spin(target);
        }
    };
    
    self.remove = function() {
        if ($parent !== undefined) {
            $parent.fadeOut(320, function() {
                _spinner.stop();
            });
        }
    };
    
    return self;
}());


var featureExtensions = (function() {
    
    // following breaks EMAPI/OpenLayers, so bail out here
    return;
    
    if (!Array.prototype.filter) {
        _c.log('extending missing JS features: Array.filter()');
        Array.prototype.filter = function(fun /*, thisp*/) {
            var len = this.length;
            
            if (typeof fun != "function") {
                throw new TypeError();
            }
            var res = new Array();
            var thisp = arguments[1];
            for (var i = 0; i < len; i++) {
                if (i in this) {
                    var val = this[i]; // in case fun mutates this
                    if (fun.call(thisp, val, i, this)) {
                        res.push(val);
                    }
                }
            }
        return res;
      };
    }    
})();

