

/* livetrance.net javascript functions. coded by devent. All rights reserved!

/**
 * Boxy 0.1.4 - Facebook-style dialog, with frills
 *
 * (c) 2008 Jason Frame
 * Licensed under the MIT License (LICENSE)
 */
 
/*
 * jQuery plugin
 *
 * Options:
 *   message: confirmation message for form submit hook (default: "Please confirm:")
 * 
 * Any other options - e.g. 'clone' - will be passed onto the boxy constructor (or
 * Boxy.load for AJAX operations)
 */
 
jQuery.fn.boxy = function(options) {
    options = options || {};
    return this.each(function() {      
        var node = this.nodeName.toLowerCase(), self = this;
        if (node == 'a') {
            jQuery(this).click(function() {
                var active = Boxy.linkedTo(this),
                    href = this.getAttribute('href'),
                    localOptions = jQuery.extend({actuator: this, title: this.title}, options);
                    
                if (active) {
                    active.show();
                } else if (href.indexOf('#') >= 0) {
                    var content = jQuery(href.substr(href.indexOf('#'))),
                        newContent = content.clone(true);
                    content.remove();
                    localOptions.unloadOnHide = false;
                    new Boxy(newContent, localOptions);
                } else { // fall back to AJAX; could do with a same-origin check
                    if (!localOptions.cache) localOptions.unloadOnHide = true;
                    Boxy.load(this.href, localOptions);
                }
                
                return false;
            });
        } else if (node == 'form') {
            jQuery(this).bind('submit.boxy', function() {
                Boxy.confirm(options.message || 'Please confirm:', function() {
                    jQuery(self).unbind('submit.boxy').submit();
                });
                return false;
            });
        }
    });
};

//
// Boxy Class

function Boxy(element, options) {
    
    this.boxy = jQuery(Boxy.WRAPPER);
    jQuery.data(this.boxy[0], 'boxy', this);
    
    this.visible = false;
    this.options = jQuery.extend({}, Boxy.DEFAULTS, options || {});
    
    if (this.options.modal) {
        this.options = jQuery.extend(this.options, {center: true, draggable: false});
    }
    
    // options.actuator == DOM element that opened this boxy
    // association will be automatically deleted when this boxy is remove()d
    if (this.options.actuator) {
        jQuery.data(this.options.actuator, 'active.boxy', this);
    }
    
    this.setContent(element || "<div></div>");
    this._setupTitleBar();
    
    this.boxy.css('display', 'none').appendTo(document.body);
    this.toTop();

    if (this.options.fixed) {
        if (jQuery.browser.msie && jQuery.browser.version < 7) {
            this.options.fixed = false; // IE6 doesn't support fixed positioning
        } else {
            this.boxy.addClass('fixed');
        }
    }
    
    if (this.options.center && Boxy._u(this.options.x, this.options.y)) {
        this.center();
    } else {
        this.moveTo(
            Boxy._u(this.options.x) ? this.options.x : Boxy.DEFAULT_X,
            Boxy._u(this.options.y) ? this.options.y : Boxy.DEFAULT_Y
        );
    }
    
    if (this.options.show) this.show();

};

Boxy.EF = function() {};

jQuery.extend(Boxy, {
    
    WRAPPER:    "<table cellspacing='0' cellpadding='0' border='0' class='boxy-wrapper'>" +
                "<tr><td class='top-left'></td><td class='top'></td><td class='top-right'></td></tr>" +
                "<tr><td class='left'></td><td class='boxy-inner'></td><td class='right'></td></tr>" +
                "<tr><td class='bottom-left'></td><td class='bottom'></td><td class='bottom-right'></td></tr>" +
                "</table>",
    
    DEFAULTS: {
        title:                  null,           // titlebar text. titlebar will not be visible if not set.
        closeable:              true,           // display close link in titlebar?
        draggable:              true,           // can this dialog be dragged?
        clone:                  false,          // clone content prior to insertion into dialog?
        actuator:               null,           // element which opened this dialog
        center:                 true,           // center dialog in viewport?
        show:                   true,           // show dialog immediately?
        modal:                  true,          // make dialog modal?
        fixed:                  false,           // use fixed positioning, if supported? absolute positioning used otherwise
        closeText:              '[close]',      // text to use for default close link
        unloadOnHide:           false,          // should this dialog be removed from the DOM after being hidden?
        clickToFront:           false,          // bring dialog to foreground on any click (not just titlebar)?
        behaviours:             Boxy.EF,        // function used to apply behaviours to all content embedded in dialog.
        afterDrop:              Boxy.EF,        // callback fired after dialog is dropped. executes in context of Boxy instance.
        afterShow:              Boxy.EF,        // callback fired after dialog becomes visible. executes in context of Boxy instance.
        afterHide:              Boxy.EF,        // callback fired after dialog is hidden. executed in context of Boxy instance.
        beforeUnload:           Boxy.EF         // callback fired after dialog is unloaded. executed in context of Boxy instance.
    },
    
    DEFAULT_X:          50,
    DEFAULT_Y:          50,
    zIndex:             1337,
    dragConfigured:     false, // only set up one drag handler for all boxys
    resizeConfigured:   false,
    dragging:           null,
    
    // load a URL and display in boxy
    // url - url to load
    // options keys (any not listed below are passed to boxy constructor)
    //   type: HTTP method, default: GET
    //   cache: cache retrieved content? default: false
    //   filter: jQuery selector used to filter remote content
    load: function(url, options) {
        
        options = options || {};
        
        var ajax = {
            url: url, type: 'GET', dataType: 'html', cache: false, success: function(html) {
                html = jQuery(html);
                if (options.filter) html = jQuery(options.filter, html);
                new Boxy(html, options);
            }
        };
        
        jQuery.each(['type', 'cache'], function() {
            if (this in options) {
                ajax[this] = options[this];
                delete options[this];
            }
        });
        
        jQuery.ajax(ajax);
        
    },
    
    // allows you to get a handle to the containing boxy instance of any element
    // e.g. <a href='#' onclick='alert(Boxy.get(this));'>inspect!</a>.
    // this returns the actual instance of the boxy 'class', not just a DOM element.
    // Boxy.get(this).hide() would be valid, for instance.
    get: function(ele) {
        var p = jQuery(ele).parents('.boxy-wrapper');
        return p.length ? jQuery.data(p[0], 'boxy') : null;
    },
    
    // returns the boxy instance which has been linked to a given element via the
    // 'actuator' constructor option.
    linkedTo: function(ele) {
        return jQuery.data(ele, 'active.boxy');
    },
    
    // displays an alert box with a given message, calling optional callback
    // after dismissal.
    alert: function(message, callback, options) {
        return Boxy.ask(message, ['OK'], callback, options);
    },
    
    // displays an alert box with a given message, calling after callback iff
    // user selects OK.
    confirm: function(message, after, options) {
        return Boxy.ask(message, ['OK', 'Cancel'], function(response) {
            if (response == 'OK') after();
        }, options);
    },
    
    // asks a question with multiple responses presented as buttons
    // selected item is returned to a callback method.
    // answers may be either an array or a hash. if it's an array, the
    // the callback will received the selected value. if it's a hash,
    // you'll get the corresponding key.
    ask: function(question, answers, callback, options) {
        
        options = jQuery.extend({modal: true, closeable: false},
                                options || {},
                                {show: true, unloadOnHide: true});
        
        var body = jQuery('<div></div>').append(jQuery('<div class="question"></div>').html(question));
        
        // ick
        var map = {}, answerStrings = [];
        if (answers instanceof Array) {
            for (var i = 0; i < answers.length; i++) {
                map[answers[i]] = answers[i];
                answerStrings.push(answers[i]);
            }
        } else {
            for (var k in answers) {
                map[answers[k]] = k;
                answerStrings.push(answers[k]);
            }
        }
        
        var buttons = jQuery('<form class="answers"></form>');
        buttons.html(jQuery.map(answerStrings, function(v) {
            return "<input type='button' value='" + v + "' />";
        }).join(' '));
        
        jQuery('input[type=button]', buttons).click(function() {
            var clicked = this;
            Boxy.get(this).hide(function() {
                if (callback) callback(map[clicked.value]);
            });
        });
        
        body.append(buttons);
        
        new Boxy(body, options);
        
    },
    
    // returns true if a modal boxy is visible, false otherwise
    isModalVisible: function() {
        return jQuery('.boxy-modal-blackout').length > 0;
    },
    
    _u: function() {
        for (var i = 0; i < arguments.length; i++)
            if (typeof arguments[i] != 'undefined') return false;
        return true;
    },
    
    _handleResize: function(evt) {
        var d = jQuery(document);
        jQuery('.boxy-modal-blackout').css('display', 'none').css({
            width: d.width(), height: d.height()
        }).css('display', 'block');
    },
    
    _handleDrag: function(evt) {
        var d;
        if (d = Boxy.dragging) {
            d[0].boxy.css({left: evt.pageX - d[1], top: evt.pageY - d[2]});
        }
    },
    
    _nextZ: function() {
        return Boxy.zIndex++;
    },
    
    _viewport: function() {
        var d = document.documentElement, b = document.body, w = window;
        return jQuery.extend(
            jQuery.browser.msie ?
                { left: b.scrollLeft || d.scrollLeft, top: b.scrollTop || d.scrollTop } :
                { left: w.pageXOffset, top: w.pageYOffset },
            !Boxy._u(w.innerWidth) ?
                { width: w.innerWidth, height: w.innerHeight } :
                (!Boxy._u(d) && !Boxy._u(d.clientWidth) && d.clientWidth != 0 ?
                    { width: d.clientWidth, height: d.clientHeight } :
                    { width: b.clientWidth, height: b.clientHeight }) );
    }

});

Boxy.prototype = {
    
    // Returns the size of this boxy instance without displaying it.
    // Do not use this method if boxy is already visible, use getSize() instead.
    estimateSize: function() {
        this.boxy.css({visibility: 'hidden', display: 'block'});
        var dims = this.getSize();
        this.boxy.css('display', 'none').css('visibility', 'visible');
        return dims;
    },
                
    // Returns the dimensions of the entire boxy dialog as [width,height]
    getSize: function() {
        return [this.boxy.width(), this.boxy.height()];
    },
    
    // Returns the dimensions of the content region as [width,height]
    getContentSize: function() {
        var c = this.getContent();
        return [c.width(), c.height()];
    },
    
    // Returns the position of this dialog as [x,y]
    getPosition: function() {
        var b = this.boxy[0];
        return [b.offsetLeft, b.offsetTop];
    },
    
    // Returns the center point of this dialog as [x,y]
    getCenter: function() {
        var p = this.getPosition();
        var s = this.getSize();
        return [Math.floor(p[0] + s[0] / 2), Math.floor(p[1] + s[1] / 2)];
    },
                
    // Returns a jQuery object wrapping the inner boxy region.
    // Not much reason to use this, you're probably more interested in getContent()
    getInner: function() {
        return jQuery('.boxy-inner', this.boxy);
    },
    
    // Returns a jQuery object wrapping the boxy content region.
    // This is the user-editable content area (i.e. excludes titlebar)
    getContent: function() {
        return jQuery('.boxy-content', this.boxy);
    },
    
    // Replace dialog content
    setContent: function(newContent) {
        newContent = jQuery(newContent).css({display: 'block'}).addClass('boxy-content');
        if (this.options.clone) newContent = newContent.clone(true);
        this.getContent().remove();
        this.getInner().append(newContent);
        this._setupDefaultBehaviours(newContent);
        this.options.behaviours.call(this, newContent);
        return this;
    },
    
    // Move this dialog to some position, funnily enough
    moveTo: function(x, y) {
        this.moveToX(x).moveToY(y);
        return this;
    },
    
    // Move this dialog (x-coord only)
    moveToX: function(x) {
        if (typeof x == 'number') this.boxy.css({left: x});
        else this.centerX();
        return this;
    },
    
    // Move this dialog (y-coord only)
    moveToY: function(y) {
        if (typeof y == 'number') this.boxy.css({top: y});
        else this.centerY();
        return this;
    },
    
    // Move this dialog so that it is centered at (x,y)
    centerAt: function(x, y) {
        var s = this[this.visible ? 'getSize' : 'estimateSize']();
        if (typeof x == 'number') this.moveToX(x - s[0] / 2);
        if (typeof y == 'number') this.moveToY(y - s[1] / 2);
        return this;
    },
    
    centerAtX: function(x) {
        return this.centerAt(x, null);
    },
    
    centerAtY: function(y) {
        return this.centerAt(null, y);
    },
    
    // Center this dialog in the viewport
    // axis is optional, can be 'x', 'y'.
    center: function(axis) {
        var v = Boxy._viewport();
        var o = this.options.fixed ? [0, 0] : [v.left, v.top];
        if (!axis || axis == 'x') this.centerAt(o[0] + v.width / 2, null);
        if (!axis || axis == 'y') this.centerAt(null, o[1] + v.height / 2);
        return this;
    },
    
    // Center this dialog in the viewport (x-coord only)
    centerX: function() {
        return this.center('x');
    },
    
    // Center this dialog in the viewport (y-coord only)
    centerY: function() {
        return this.center('y');
    },
    
    // Resize the content region to a specific size
    resize: function(width, height, after) {
        if (!this.visible) return;
        var bounds = this._getBoundsForResize(width, height);
        this.boxy.css({left: bounds[0], top: bounds[1]});
        this.getContent().css({width: bounds[2], height: bounds[3]});
        if (after) after(this);
        return this;
    },
    
    // Tween the content region to a specific size
    tween: function(width, height, after) {
        if (!this.visible) return;
        var bounds = this._getBoundsForResize(width, height);
        var self = this;
        this.boxy.stop().animate({left: bounds[0], top: bounds[1]});
        this.getContent().stop().animate({width: bounds[2], height: bounds[3]}, function() {
            if (after) after(self);
        });
        return this;
    },
    
    // Returns true if this dialog is visible, false otherwise
    isVisible: function() {
        return this.visible;    
    },
    
    // Make this boxy instance visible
    show: function() {
        if (this.visible) return;
        if (this.options.modal) {
            var self = this;
            if (!Boxy.resizeConfigured) {
                Boxy.resizeConfigured = true;
                jQuery(window).resize(function() { Boxy._handleResize(); });
            }
            this.modalBlackout = jQuery('<div class="boxy-modal-blackout"></div>')
                .css({zIndex: Boxy._nextZ(),
                      opacity: 0.7,
                      width: jQuery(document).width(),
                      height: jQuery(document).height()})
                .appendTo(document.body);
            this.toTop();
            if (this.options.closeable) {
                jQuery(document.body).bind('keypress.boxy', function(evt) {
                    var key = evt.which || evt.keyCode;
                    if (key == 27) {
                        self.hide();
                        jQuery(document.body).unbind('keypress.boxy');
                    }
                });
            }
        }
        this.boxy.stop().css({opacity: 1}).show();
        this.visible = true;
        this._fire('afterShow');
        return this;
    },
    
    // Hide this boxy instance
    hide: function(after) {
        if (!this.visible) return;
        var self = this;
        if (this.options.modal) {
            jQuery(document.body).unbind('keypress.boxy');
            this.modalBlackout.animate({opacity: 0}, function() {
                jQuery(this).remove();
            });
        }
        this.boxy.stop().animate({opacity: 0}, 300, function() {
            self.boxy.css({display: 'none'});
            self.visible = false;
            self._fire('afterHide');
            if (after) after(self);
            if (self.options.unloadOnHide) self.unload();
        });
        return this;
    },
    
    toggle: function() {
        this[this.visible ? 'hide' : 'show']();
        return this;
    },
    
    hideAndUnload: function(after) {
        this.options.unloadOnHide = true;
        this.hide(after);
        return this;
    },
    
    unload: function() {
        this._fire('beforeUnload');
        this.boxy.remove();
        if (this.options.actuator) {
            jQuery.data(this.options.actuator, 'active.boxy', false);
        }
    },
    
    // Move this dialog box above all other boxy instances
    toTop: function() {
        this.boxy.css({zIndex: Boxy._nextZ()});
        return this;
    },
    
    // Returns the title of this dialog
    getTitle: function() {
        return jQuery('> .title-bar h2', this.getInner()).html();
    },
    
    // Sets the title of this dialog
    setTitle: function(t) {
        jQuery('> .title-bar h2', this.getInner()).html(t);
        return this;
    },
    
    //
    // Don't touch these privates
    
    _getBoundsForResize: function(width, height) {
        var csize = this.getContentSize();
        var delta = [width - csize[0], height - csize[1]];
        var p = this.getPosition();
        return [Math.max(p[0] - delta[0] / 2, 0),
                Math.max(p[1] - delta[1] / 2, 0), width, height];
    },
    
    _setupTitleBar: function() {
        if (this.options.title) {
            var self = this;
            var tb = jQuery("<div class='title-bar'></div>").html("<h2>" + this.options.title + "</h2>");
            if (this.options.closeable) {
                tb.append(jQuery("<a href='#' class='close'></a>").html(this.options.closeText));
            }
            if (this.options.draggable) {
                tb[0].onselectstart = function() { return false; }
                tb[0].unselectable = 'on';
                tb[0].style.MozUserSelect = 'none';
                if (!Boxy.dragConfigured) {
                    jQuery(document).mousemove(Boxy._handleDrag);
                    Boxy.dragConfigured = true;
                }
                tb.mousedown(function(evt) {
                    self.toTop();
                    Boxy.dragging = [self, evt.pageX - self.boxy[0].offsetLeft, evt.pageY - self.boxy[0].offsetTop];
                    jQuery(this).addClass('dragging');
                }).mouseup(function() {
                    jQuery(this).removeClass('dragging');
                    Boxy.dragging = null;
                    self._fire('afterDrop');
                });
            }
            this.getInner().prepend(tb);
            this._setupDefaultBehaviours(tb);
        }
    },
    
    _setupDefaultBehaviours: function(root) {
        var self = this;
        if (this.options.clickToFront) {
            root.click(function() { self.toTop(); });
        }
        jQuery('.close', root).click(function() {
            self.hide();
            return false;
        }).mousedown(function(evt) { evt.stopPropagation(); });
    },
    
    _fire: function(event) {
        this.options[event].call(this);
    }
    
};
/*####################################################################################
######################################################################################
######################################################################################
######################################################################################
####################################################################################*/

var animatedcollapse={
divholders: {}, //structure: {div.id, div.attrs, div.$divref}
divgroups: {}, //structure: {groupname.count, groupname.lastactivedivid}
statusholders: {}, //structure: {[statuselement.id, stype, [opensrc, closedsrc]], $target}
lastactiveingroup: {}, //structure: {lastactivediv.id}

show:function(divids){ //public method
    if (typeof divids=="object"){
        for (var i=0; i<divids.length; i++)
            this.showhide(divids[i], "show")
    }
    else
        this.showhide(divids, "show")
},

hide:function(divids){ //public method
    if (typeof divids=="object"){
        for (var i=0; i<divids.length; i++)
            this.showhide(divids[i], "hide")
    }
    else
        this.showhide(divids, "hide")
},

toggle:function(divid){ //public method
    if (typeof divid=="object")
        divid=divid[0]
    this.showhide(divid, "toggle")
},

addDiv:function(divid, attrstring){ //public function
    this.divholders[divid]=({id: divid, $divref: null, attrs: attrstring})
    this.divholders[divid].getAttr=function(name){ //assign getAttr() function to each divholder object
        var attr=new RegExp(name+"=([^,]+)", "i") //get name/value config pair (ie: width=400px,)
        return (attr.test(this.attrs) && parseInt(RegExp.$1)!=0)? RegExp.$1 : null //return value portion (string), or 0 (false) if none found
    }
    this.currentid=divid //keep track of current div object being manipulated (in the event of chaining)
    return this
},

showhide:function(divid, action){
    var $divref=this.divholders[divid].$divref //reference collapsible DIV
    if (this.divholders[divid] && $divref.length==1){ //if DIV exists
        var targetgroup=this.divgroups[$divref.attr('groupname')] //find out which group DIV belongs to (if any)
        if ($divref.attr('groupname') && targetgroup.count>1 && (action=="show" || action=="toggle" && $divref.css('display')=='none')){ //If current DIV belongs to a group
            if (targetgroup.lastactivedivid && targetgroup.lastactivedivid!=divid) //if last active DIV is set
                this.slideengine(targetgroup.lastactivedivid, 'hide') //hide last active DIV within group first
                this.slideengine(divid, 'show')
            targetgroup.lastactivedivid=divid //remember last active DIV
        }
        else{
            this.slideengine(divid, action)
        }
    }
},

slideengine:function(divid, action){
    var $divref=this.divholders[divid].$divref
    if (this.divholders[divid] && $divref.length==1){ //if this DIV exists
        var animateSetting={height: action}
        if ($divref.attr('fade'))
            animateSetting.opacity=action
        $divref.animate(animateSetting, $divref.attr('speed')? parseInt($divref.attr('speed')) : 500, function(){
            if (animatedcollapse.ontoggle){
                try{
                    animatedcollapse.ontoggle(jQuery, $divref.get(0), $divref.css('display'))
                }
                catch(e){
                    alert("An error exists inside your \"ontoggle\" function:\n\n"+e+"\n\nAborting execution of function.")
                }
            }
        })
        return false
    }
},

generatemap:function(){
    var map={}
    for (var i=0; i<arguments.length; i++){
        if (arguments[i][1]!=null){ //do not generate name/value pair if value is null
            map[arguments[i][0]]=arguments[i][1]
        }
    }
    return map
},

init:function(){
    var ac=this
    jQuery(document).ready(function($){
        animatedcollapse.ontoggle=animatedcollapse.ontoggle || null
        var urlparamopenids=animatedcollapse.urlparamselect() //Get div ids that should be expanded based on the url (['div1','div2',etc])
        var persistopenids=ac.getCookie('acopendivids') //Get list of div ids that should be expanded due to persistence ('div1,div2,etc')
        var groupswithpersist=ac.getCookie('acgroupswithpersist') //Get list of group names that have 1 or more divs with "persist" attribute defined
        if (persistopenids!=null) //if cookie isn't null (is null if first time page loads, and cookie hasnt been set yet)
            persistopenids=(persistopenids=='nada')? [] : persistopenids.split(',') //if no divs are persisted, set to empty array, else, array of div ids
        groupswithpersist=(groupswithpersist==null || groupswithpersist=='nada')? [] : groupswithpersist.split(',') //Get list of groups with divs that are persisted
        jQuery.each(ac.divholders, function(){ //loop through each collapsible DIV object
            this.$divref=$('#'+this.id)
            if ((this.getAttr('persist') || jQuery.inArray(this.getAttr('group'), groupswithpersist)!=-1) && persistopenids!=null){ //if this div carries a user "persist" setting, or belong to a group with at least one div that does
                var cssdisplay=(jQuery.inArray(this.id, persistopenids)!=-1)? 'block' : 'none'
            }
            else{
                var cssdisplay=this.getAttr('hide')? 'none' : null
            }
            if (urlparamopenids[0]=="all" || jQuery.inArray(this.id, urlparamopenids)!=-1){ //if url parameter string contains the single array element "all", or this div's ID
                cssdisplay='block' //set div to "block", overriding any other setting
            }
            else if (urlparamopenids[0]=="none"){
                cssdisplay='none' //set div to "none", overriding any other setting
            }
            this.$divref.css(ac.generatemap(['height', this.getAttr('height')], ['display', cssdisplay]))
            this.$divref.attr(ac.generatemap(['groupname', this.getAttr('group')], ['fade', this.getAttr('fade')], ['speed', this.getAttr('speed')]))
            if (this.getAttr('group')){ //if this DIV has the "group" attr defined
                var targetgroup=ac.divgroups[this.getAttr('group')] || (ac.divgroups[this.getAttr('group')]={}) //Get settings for this group, or if it no settings exist yet, create blank object to store them in
                targetgroup.count=(targetgroup.count||0)+1 //count # of DIVs within this group
                if (jQuery.inArray(this.id, urlparamopenids)!=-1){ //if url parameter string contains this div's ID
                    targetgroup.lastactivedivid=this.id //remember this DIV as the last "active" DIV (this DIV will be expanded). Overrides other settings
                    targetgroup.overridepersist=1 //Indicate to override persisted div that would have been expanded
                }
                if (!targetgroup.lastactivedivid && this.$divref.css('display')!='none' || cssdisplay=="block" && typeof targetgroup.overridepersist=="undefined") //if this DIV was open by default or should be open due to persistence                                
                    targetgroup.lastactivedivid=this.id //remember this DIV as the last "active" DIV (this DIV will be expanded)
                this.$divref.css({display:'none'}) //hide any DIV that's part of said group for now
            }
        }) //end divholders.each
        jQuery.each(ac.divgroups, function(){ //loop through each group
            if (this.lastactivedivid && urlparamopenids[0]!="none") //show last "active" DIV within each group (one that should be expanded), unless url param="none"
                ac.divholders[this.lastactivedivid].$divref.show()
        })
        if (animatedcollapse.ontoggle){
            jQuery.each(ac.divholders, function(){ //loop through each collapsible DIV object and fire ontoggle event
                animatedcollapse.ontoggle(jQuery, this.$divref.get(0), this.$divref.css('display'))
            })
        }
/* //reserved for future implementation
        var $allcontrols=$('a[rel]').filter('[@rel^="collapse["], [@rel^="expand["], [@rel^="toggle["]') //get all elements on page with rel="collapse[]", "expand[]" and "toggle[]"
        $allcontrols.each(function(){ //loop though each control link
            this._divids=this.getAttribute('rel').replace(/(^\w+)|(\s+)/g, "").replace(/[\[\]']/g, "") //cache value 'div1,div2,etc' within identifier[div1,div2,etc]
            $(this).click(function(){ //assign click behavior to each control link
                var relattr=this.getAttribute('rel')
                var divids=(this._divids=="")? [] : this._divids.split(',') //convert 'div1,div2,etc' to array 
                if (divids.length>0){
                    animatedcollapse[/expand/i.test(relattr)? 'show' : /collapse/i.test(relattr)? 'hide' : 'toggle'](divids) //call corresponding public function
                    return false
                }
            }) //end control.click
        })// end control.each
*/
        $(window).bind('unload', function(){
            ac.uninit()
        })
    }) //end doc.ready()
},

uninit:function(){
    var opendivids='', groupswithpersist=''
    jQuery.each(this.divholders, function(){
        if (this.$divref.css('display')!='none'){
            opendivids+=this.id+',' //store ids of DIVs that are expanded when page unloads: 'div1,div2,etc'
        }
        if (this.getAttr('group') && this.getAttr('persist'))
            groupswithpersist+=this.getAttr('group')+',' //store groups with which at least one DIV has persistance enabled: 'group1,group2,etc'
    })
    opendivids=(opendivids=='')? 'nada' : opendivids.replace(/,$/, '')
    groupswithpersist=(groupswithpersist=='')? 'nada' : groupswithpersist.replace(/,$/, '')
    this.setCookie('acopendivids', opendivids)
    this.setCookie('acgroupswithpersist', groupswithpersist)
},

getCookie:function(Name){ 
    var re=new RegExp(Name+"=[^;]*", "i"); //construct RE to search for target name/value pair
    if (document.cookie.match(re)) //if cookie found
        return document.cookie.match(re)[0].split("=")[1] //return its value
    return null
},

setCookie:function(name, value, days){
    if (typeof days!="undefined"){ //if set persistent cookie
        var expireDate = new Date()
        expireDate.setDate(expireDate.getDate()+days)
        document.cookie = name+"="+value+"; path=/; expires="+expireDate.toGMTString()
    }
    else //else if this is a session only cookie
        document.cookie = name+"="+value+"; path=/"
},

urlparamselect:function(){
    window.location.search.match(/expanddiv=([\w\-_,]+)/i) //search for expanddiv=divid or divid1,divid2,etc
    return (RegExp.$1!="")? RegExp.$1.split(",") : []
}

}
/*#############################################################
###############################################################
#############################################################*/


function newImage() { if (document.images) document.images.reloadimage.src = 'scr/captcha.php?' + (new Date()).getTime(); }
function cbor(r) {
    if(r.className == "reg regnormal") { r.className = "reg reghover"; }
    else if(r.className == "reg reghover") { r.className = "reg regnormal"; }
}
function login_inputs_change(flag, sender, type) {
    switch(flag) {
        case "focus":
            if(type == "register") { cbor(sender); }
            if(sender.value == sender.defaultValue) { sender.value = ""; }
        break;
        case "blur":
            if(type == "register") { cbor(sender); ajax_check(sender,"register"); }
            if(sender.value == "") { sender.value = sender.defaultValue; }
        break;
    }
}

function ajax_check(object,page,type) {
    var xmlhttp=false;
  try {
    xmlhttp = new ActiveXObject('Msxml2.XMLHTTP');
  } catch (e) {
    try {
      xmlhttp = new
      ActiveXObject('Microsoft.XMLHTTP');
    } catch (E) {
      xmlhttp = false;
    }
  }
  if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
    xmlhttp = new XMLHttpRequest();
  }
  var url = 'scr/ajax.php?tt=check&p=' + page + '&t=' + object.name + '&val='+ object.value;
  xmlhttp.open('GET', url, true);
  xmlhttp.onreadystatechange=function() {
    if (xmlhttp.readyState==4) {
      var content = xmlhttp.responseText;
   if( content ){
        if(content.match('dev')) {
            object.className = "reg regaccept";
        } else {
            object.className = "reg regerror";
        }
      }
    }
  }
  xmlhttp.send(null)
  return;
}
function music_cats(func, value) {
    switch(func) {
        case "hover":
            if(value.className == "mcats") { value.className = "mcats_hover"; }
            else { value.className = "mcats"; }
        break;
        case "redirect":
            window.location = "music/cat/" + value;
        break;
    }
}

function ajax_vote(type, vote, object_id) {
    var div = document.getElementById("voting");
    $("#voting").fadeOut("slow",function(){
        var xmlhttp=false;
      try {
        xmlhttp = new ActiveXObject('Msxml2.XMLHTTP');
      } catch (e) {
        try {
          xmlhttp = new
          ActiveXObject('Microsoft.XMLHTTP');
        } catch (E) {
          xmlhttp = false;
        }
      }
      if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
        xmlhttp = new XMLHttpRequest();
      }
      var url = 'scr/ajax.php?tt=vote&v=' + type + '&id=' + object_id + '&vote=' + vote;
      xmlhttp.open('GET', url, true);
      xmlhttp.onreadystatechange=function() {
        if (xmlhttp.readyState==4) {
          var content = xmlhttp.responseText;
               if(content){
                div.innerHTML = content;
               }
          }
      }
       xmlhttp.send(null)
       return;
   });
   $("#voting").fadeIn("slow");
}
function bbcode(open_tag, close_tag) {
   var obj = document.getElementById('text');
   var spacer;
   if(obj.value.length > 0) {
      spacer = " ";
   } else {
      spacer = "";
   }
   var begining_text = obj.value.substr(0, obj.selectionStart);
   var selected_text = obj.value.substr(obj.selectionStart, obj.selectionEnd);
   var end_text = obj.value.substr(obj.selectionEnd, obj.value.length);

   var caret_position = obj.selectionStart;
   var text_to_caret = obj.value.substr(0, caret_position);
   var text_after_caret = obj.value.substr(caret_position, obj.value.length);

   // If there is a selection
   if(obj.selectionStart != obj.selectionEnd) {
      obj.value = begining_text + open_tag + selected_text + close_tag + end_text
   } else {
   // If there is not a selection
      obj.value = text_to_caret + open_tag + close_tag + text_after_caret
   }
   //obj.value = obj.value + spacer + text;

}
function getComments(type, id, page, def) {
    var div = document.getElementById("show_comments");
    var xmlhttp=false;
  try {
    xmlhttp = new ActiveXObject('Msxml2.XMLHTTP');
  } catch (e) {
    try {
      xmlhttp = new
      ActiveXObject('Microsoft.XMLHTTP');
    } catch (E) {
      xmlhttp = false;
    }
  }
  if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
    xmlhttp = new XMLHttpRequest();
  }
  var url = 'scr/ajax.php?tt=pagination&v=' + type + '&id=' + id + '&page=' + page;
  xmlhttp.open('GET', url, true);
  xmlhttp.onreadystatechange=function() {
    if (xmlhttp.readyState==4) {
      var content = xmlhttp.responseText;
   if(content){
   $("#show_comments").fadeOut("fast",function(){
   div.innerHTML = content;
   });
   if(def == "default") { javascript:animatedcollapse.toggle('show_comments'); }
   else { $("#show_comments").fadeIn("slow"); }
      }
    }
  }
  xmlhttp.send(null)
  return;
}
function ctc(val,val2,val3) {
    var divi = document.getElementById('comentarite');
    if(val == "1") {
        divi.innerHTML = '<a class="cls" href="javascript:;" onclick="javascript:animatedcollapse.toggle(\'show_comments\'); ctc(\'2\',\'' + val2 + '\',\'' + val3 + '\');">Скрийте коментарите</a>';
    } else {
        divi.innerHTML = '<a class="cls" href="javascript:;" onclick="javascript:getComments(\'1\',\'' + val3 + '\',\'1\',\'default\'); ctc(\'1\',\'' + val2 + '\',\'' + val3 + '\');">Вижте коментарите(' + val2 + ')</a>';
    }
}
function report_comment(val,val2) {
    $.get("scr/ajax.php", { tt: "report", val: val, val2: val2 } );
    jAlert('success', 'Съобщението е маркирано като нередно.<br />Предстой преглед на вашият репорт от екипа на сайта<br /> Благодарим ви!', 'Съобщението е маркирано успешно');
}
function radio_show_help(val) {
    if(val == "1") { 
        var message = "За да може радио станцията да се слуша през сайта трябва да направите следното нещо:<br /><br />1. Зареждате адреса на радиото във вашият winamp или друг вид плеър.<br />2. Давате десен бутон -> view info(за winamp)<br /> 3. Копирате адреса и го поставяте в полето \"Адрес за флаш плеър-а\"<br /><br />Благодарим на всеки потребител, който отделя от времето си да направи горните действия.";
        var title = "Как да направим радиото ни да се слуша от сайта?";
    }
    if(val == "2") {
        var message = "За да може радио станцията да се слуша през сайта т.е през флаш плеъра, трябва да си поиграете малко. Това поле не е задължително, но все пак е препорачително да качвате и този линк.<br />За да видите как става натиснете на \"<b>Как да видя адреса на радио станцията за флаш плеъра?</b>\"";
        var title = "Какво е това поле?";
    }
    jAlert('info', message, title);
}
function openPopup(url,width,height){
    window.open(url,'popup','toolbar=0,location=0,directories=0,titlebar=0,statusbar=0,menubar=0,scrollbars=0,resizable=1,width='+width+',height='+height);
}
function ismaxlength(obj){
    var mlength=obj.getAttribute? parseInt(obj.getAttribute("maxlength")) : ""
    if (obj.getAttribute && obj.value.length>mlength)
    obj.value=obj.value.substring(0,mlength)
    document.getElementById('symbols').innerHTML = mlength - obj.value.length;
}
function add2fav(type,id) {
    $.get("scr/ajax.php", { tt: "add2fav", type: type, id: id },
    function(data){
        jAlert('info', data, "Информация: добавяне в любими");
    });

}
function poll_vote(poll_id) {  
    var str = $("#pollz").serialize();
    var he = $("#poll_div").height() + 51;
    $.post("scr/ajax.php", { tt: "poll", id: poll_id, date: str,  },
    function(data){
        $("#ipoll").hide();
        $("#ipoll").html(data);
            $("#poll_div").fadeOut("slow", function() {
                $("#ipoll").css({ height: he });
                $("#ipoll").fadeIn("slow");
            });
    });
}
function get_poll_info(poll_id) {
    $.get("scr/ajax.php", { tt: "poll_info", id: poll_id },
    function(data){
        jAlert('info', data, "Информация за анкетата");
    });


}
function coa(obj) {
    if(obj == "other") { document.getElementById("other_author").style.display = 'block'; }
    else { document.getElementById("other_author").style.display = 'none'; }
}
var XxX = "1";
function addNewInput() {
   if(XxX == "3") {
       jAlert('error', "Можете да задавате максимум 3 снимки!", "Грешка");
   } else {
       alert(XxX);
       var divid = document.getElementById('addNew');
       var text = divid.innerHTML;
       divid.innerHTML = text + '<input type="file" name="pics[]" class="inpalbum" style="margin-top: 3px;" /><br />';
       var XxX = XxX + 1;
   }
}
function addNewLink(val1,val2) {
    if(val1 == "" || val2 == "") { jAlert('error','И двете полета са задължителни за попълване!!','Грешка!'); }
    else { 
        var ndiv = document.getElementById('mainmenus');
        var randomnumber=Math.floor(Math.random()*11)
        var newdiv = "newdiv" + randomnumber;
        ndiv.innerHTML = ndiv.innerHTML + '<div id=' + newdiv + ' class="spec" style="display: none;"><a style="text-align: left;" href="' + val2 + '"><img src="templates/default/img/added.png" width="7" height="7" alt="Мой линк" /> ' + val1 + '</a></div>';
        $.get("scr/ajax.php", { tt: "addnewlink", val1: val1, val2: val2 },
        function(data){
            if(data != "error") {
                $("#" + newdiv + "").slideDown("slow", function() {
                    animatedcollapse.toggle('addnewlink');
                });
            }
        });
    }
}
function removeMyLink(id) {
    $.get("scr/ajax.php", { tt: "removeMyLink", id: id },
    function(data){
        if(data != "error") {
            $("#ml" + id + "").slideUp("slow");
        }
    });
}
//global variables that can be used by ALL the function son this page.
var inputs;
var imgFalse = 'templates/default/img/unchecked.gif';
var imgTrue = 'templates/default/img/checked.gif';

//this function runs when the page is loaded, put all your other onload stuff in here too.
function init() {
replaceChecks();
}

function replaceChecks() {

//get all the input fields on the page
inputs = document.getElementsByTagName('input');

//cycle trough the input fields
for(var i=0; i < inputs.length; i++) {

//check if the input is a checkbox
if(inputs[i].getAttribute('type') == 'checkbox') {

//create a new image
var img = document.createElement('img');

//check if the checkbox is checked
if(inputs[i].checked) {
img.src = imgTrue;
} else {
img.src = imgFalse;
}

//set image ID and onclick action
img.id = 'checkImage'+i;

//set image
img.onclick = new Function('checkChange('+i+')');
//place image in front of the checkbox
inputs[i].parentNode.insertBefore(img, inputs[i]);

//hide the checkbox
inputs[i].style.display='none';
}
}
}

//change the checkbox status and the replacement image
function checkChange(i) {

if(inputs[i].checked) {
inputs[i].checked = '';
document.getElementById('checkImage'+i).src=imgFalse;
} else {
inputs[i].checked = 'checked';
document.getElementById('checkImage'+i).src=imgTrue;
}
}
window.onload = init;

$(document).ready(function(){

    $("ul.subnav").parent().append("<span></span>"); //Only shows drop down trigger when js is enabled (Adds empty span tag after ul.subnav*)

    $("ul.topnav li span").click(function() { //When trigger is clicked...

        //Following events are applied to the subnav itself (moving subnav up and down)
        $(this).parent().find("ul.subnav").slideDown('fast').show(); //Drop down the subnav on click

        $(this).parent().hover(function() {
        }, function(){
            $(this).parent().find("ul.subnav").slideUp('slow'); //When the mouse hovers out of the subnav, move it back up
        });

        //Following events are applied to the trigger (Hover events for the trigger)
        }).hover(function() {
            $(this).addClass("subhover"); //On hover over, add class "subhover"
        }, function(){    //On Hover Out
            $(this).removeClass("subhover"); //On hover out, remove class "subhover"
    });

});


/**
 * Easy Widgets 2.0 for jQuery and jQuery UI
 *
 * David Esperalta <http://www.davidesperalta.com/>
 * 
 * More information, examples and latest version in the website:
 * <http://www.bitacora.davidesperalta.com/archives/projects/easywidgets/>
 *
 * I based my work on a tutorial writen by James Padolsey
 * <http://nettuts.com/tutorials/javascript-ajax/inettuts/>
 *
 * You should have received a copy of the GNU General Public License
 * along with Easy Widgets. If not, see <http://www.gnu.org/licenses/>
 *
 */
(function($){

  ///////////////////////////
  // Public plugin methods //
  ///////////////////////////
  
  /**
   * Main public method of plugin
   *
   * Call this method to initialize the plugin, that prepare all the available
   * widgets in the document, and execute the appropiate task on every widget.
   *
   * Basically call the InitializeWidgets() private function, with the second
   * param by default: using this method we not prepare widgets on demand, but
   * prepare all widgets found in the document.
   *
   * See the mentioned function for more details, and how we use this function
   * too in another plugin public method: AddEasyWidget(), see it for details.
   *
   * @access public
   * @see InitializeWidgets()
   * @param settings Array with the plugin settings
   * @return Boolean True in every case
   *
   */
  $.fn.EasyWidgets = function(settings){
    InitializeWidgets(settings, false);
    return true;
  };

  /**
   * Add a new widget "on demand"
   *
   * This public method can be use to add a new widget "on demand" into certain
   * place. The method need the HTML markup for widget, and this can specify
   * all the available widget options.
   *
   * In this method we use the private InitializeWidgets() function, also used
   * in another public method of the plugin: EasyWidgets(). Note that in this
   * case the second param for this funtion specify that in this case we want
   * to add a widget "on demand".
   *
   * For more details see the refered private function.
   *
   * @access public
   * @see InitializeWidgets()
   * @param html String Widget HTML markup
   * @param placeId String Element ID to place the Widget
   * @param settings Array with the plugin settings
   * @return Boolean True if widget is finally added, False if not
   *
   */
  $.fn.AddEasyWidget = function(html, placeId, settings){
    var canAdd = true;
    var widget = $(html);
    var s = $.extend(true, $.fn.EasyWidgets.defaults, settings);
    if($.isFunction(s.callbacks.onAddQuery)){
      canAdd = s.callbacks.onAddQuery(widget, placeId);
    }
    if(canAdd){
      $('#'+placeId).append(html);
      if($.isFunction(s.callbacks.onAdd)){
        s.callbacks.onAdd(widget, placeId);
      }
      InitializeWidgets(s, true);
      return true;
    }else{
      return false;
    }
  };

  /**
   * Disable all widgets (fix then) in document
   *
   * This public method can be use to fix the widgets on document, in other
   * words, disable the widgets, because the user cant move this after the
   * widgets as been disables.
   * 
   * @access public
   * @see EnableEasyWidgets()
   * @param settings Array with the plugin settings
   * @return Boolean True if widgets are finally disables, False if not
   *
   */
  $.fn.DisableEasyWidgets = function(settings){
    var canDisable = true;
    var s = $.extend(true, $.fn.EasyWidgets.defaults, settings);
    if($.isFunction(s.callbacks.onDisableQuery)){
      canDisable = s.callbacks.onDisableQuery();
    }
    if(canDisable){
      $(s.selectors.places).sortable('disable');
      $(s.selectors.widget).each(function(){
        var widget = $(this);
        if(widget.hasClass(s.options.movable)){
          widget.find(s.selectors.header).css('cursor', 'default');
        }
      });
      if($.isFunction(s.callbacks.onDisable)){
        s.callbacks.onDisable();
      }
      SetCookie(s.cookies.disableName, 1, s);
      return true;
    }else{
      return false;
    }
  };

  /**
   * Enable all widgets (make movables) in document
   *
   * This public method can be use to make movables the widgets on document,
   * in other words, enable the widgets, because the user can move this after
   * the widgets as been enables.
   *
   * Note that the widgets are enables by default, so, this method have sense
   * in case that you use before another method of plugin: DisableEasyWidgets()
   *
   * @access public
   * @see DisableEasyWidgets()
   * @param settings Array with the plugin settings
   * @return Boolean True if widgets are finally enables, False if not
   *
   */
  $.fn.EnableEasyWidgets = function(settings){
    var canEnable = true;
    var s = $.extend(true, $.fn.EasyWidgets.defaults, settings);
    if($.isFunction(s.callbacks.onEnableQuery)){
      canEnable = s.callbacks.onEnableQuery();
    }
    if(canEnable){
      $(s.selectors.places).sortable('enable');
      $(s.selectors.widget).each(function(){
        var widget = $(this);
        if(widget.hasClass(s.options.movable)){
          widget.find(s.selectors.header).css('cursor', 'move');
        }
      });
      if($.isFunction(s.callbacks.onEnable)){
        s.callbacks.onEnable();
      }
      if(s.behaviour.useCookies){
        SetCookie(s.cookies.disableName, 0, s);
      }
      return true;
    }else{
      return false;
    }
  };

  /**
   * Hide all widgets in document
   *
   * This public method can be use to hide all the document visible widgets.
   * Note that this method and related is thinking if you use the plugin
   * cookies feature.
   *
   * In other case, you can use directly something like this:
   *
   * $('widgets-class-selector').hide();
   *
   * So, this method can sense if you use the plugin cookies feature, because
   * the plugin update the appropiate cookie with the needed information, to
   * mantain the widgets hidden even if user refresh the page.
   *
   * @access public
   * @see HideEasyWidget()
   * @see ShowEasyWidgets()
   * @param settings Array with the plugin settings
   * @return Boolean True in every case
   *
   */
  $.fn.HideEasyWidgets = function(settings){
    var s = $.extend(true, $.fn.EasyWidgets.defaults, settings);
    $(s.selectors.widget+':visible').each(function(){
      var canHide = true;
      var thisWidget = $(this);
      var thisWidgetId = thisWidget.attr('id');
      if($.isFunction(s.callbacks.onHideQuery)){
        canHide = s.callbacks.onHideQuery(thisWidget);
      }
      if(canHide){
        ApplyEffect(
          thisWidget,
          s.effects.widgetHide,
          s.effects.effectDuration,
          false
        );
        if(s.behaviour.useCookies && thisWidgetId){
          UpdateCookie(thisWidgetId, s.cookies.closeName, s);
        }
        if($.isFunction(s.callbacks.onHide)){
          s.callbacks.onHide(thisWidget);
        }
      }
    });
    return true;
  };

  /**
   * Show all widgets in document
   *
   * This public method can be use to show all the document hidden widgets.
   * Note that this method and related is thinking if you use the plugin
   * cookies feature.
   *
   * In other case, you can use directly something like this:
   *
   * $('widgets-class-selector').show();
   *
   * So, this method can sense if you use the plugin cookies feature, because
   * the plugin update the appropiate cookie with the needed information, to
   * mantain the widgets showing even if user refresh the page.
   *
   * @access public
   * @see ShowEasyWidget()
   * @see HideEasyWidgets()
   * @param settings Array with the plugin settings
   * @return Boolean True in every case
   *
   */
  $.fn.ShowEasyWidgets = function(settings){
    var s = $.extend(true, $.fn.EasyWidgets.defaults, settings);
    $(s.selectors.widget+':hidden').each(function(){
      var canShow = true;
      var widget = $(this);
      var widgetId = widget.attr('id');
      var haveId = ($.trim(widgetId) != '');
      if($.isFunction(s.callbacks.onShowQuery)){
        canShow = s.callbacks.onShowQuery(widget);
      }
      if(canShow){
        ApplyEffect(
          widget,
          s.effects.widgetShow,
          s.effects.effectDuration,
          true
        );
        if(haveId && s.behaviour.useCookies){
          CleanCookie(widgetId, s.cookies.closeName, s);
        }
        if($.isFunction(s.callbacks.onShow)){
          s.callbacks.onShow(widget);
        }
      }
    });
    return true;
  };

  /**
   * Show an individual widget
   *
   * This public method can be use to show an individual hidden widget.
   * Note that this method and related is thinking if you use the plugin
   * cookies feature.
   *
   * In other case, you can use directly something like this:
   *
   * $('widget-id-selector').show();
   *
   * So, this method can sense if you use the plugin cookies feature, because
   * the plugin update the appropiate cookie with the needed information, to
   * mantain the widgets showing even if user refresh the page.
   *
   * @access public
   * @see HideEasyWidget()
   * @see ShowEasyWidgets()
   * @param widgetId String Widget element identifier
   * @param settings Array with the plugin settings
   * @return Boolean True if widget finally is show, False if not
   *
   */
  $.fn.ShowEasyWidget = function(widgetId, settings){
    var canShow = true;
    var widget = $('#'+widgetId);
    if(widget.css('display') == 'none'){
      var s = $.extend(true, $.fn.EasyWidgets.defaults, settings);
      if($.isFunction(s.callbacks.onShowQuery)){
        canShow = s.callbacks.onShowQuery(widget);
      }
      if(canShow){
        ApplyEffect(
          widget,
          s.effects.widgetShow,
          s.effects.effectDuration,
          true
        );
        if(s.behaviour.useCookies){
          CleanCookie(widgetId, s.cookies.closeName, s);
        }
        if($.isFunction(s.callbacks.onShow)){
          s.callbacks.onShow(widget);
        }
        return true;
      }else{
        return false;
      }
    }else{
      return false;
    }
  };

  /**
   * Hide an individual widget
   *
   * This public method can be use to hide an individual visible widget.
   * Note that this method and related is thinking if you use the plugin
   * cookies feature.
   *
   * In other case, you can use directly something like this:
   *
   * $('widget-id-selector').hide();
   *
   * So, this method can sense if you use the plugin cookies feature, because
   * the plugin update the appropiate cookie with the needed information, to
   * mantain the widgets showing even if user refresh the page.
   *
   * @access public
   * @see ShowEasyWidget()
   * @see HideEasyWidgets()
   * @param widgetId String Widget element identifier
   * @param settings Array with the plugin settings
   * @return Boolean True if widget finally is hide, False if not
   *
   */
  $.fn.HideEasyWidget = function(widgetId, settings){
    var canHide = true;
    var widget = $('#'+widgetId);
    if(widget.css('display') != 'none'){
      var s = $.extend(true, $.fn.EasyWidgets.defaults, settings);
      if($.isFunction(s.callbacks.onHideQuery)){
        canHide = s.callbacks.onHideQuery(widget);
      }
      if(canHide){
        ApplyEffect(
          widget,
          s.effects.widgetHide,
          s.effects.effectDuration,
          false
        );
        if(s.behaviour.useCookies){
          UpdateCookie(widgetId, s.cookies.closeName, s);
        }
        if($.isFunction(s.callbacks.onHide)){
          s.callbacks.onHide(widget);
        }
        return true;
      }else{
        return false;
      }
    }else{
      return false;
    }
  };

  /////////////////////////////
  // Plugin default settings //
  /////////////////////////////

  /**
   * Plugin default settings
   *
   * This is the settings that plugin use in case that you not provide your
   * own plugin settings. Also, you dont need to provide all the settings, but
   * change only that you need: the plugin use the default settings that you
   * not provided, and also the settings that you provide.
   *
   * In other words, the plugin merge your own settings with plugin defaults.
   * 
   */
  $.fn.EasyWidgets.defaults = {

    // Behaviour of the plugin
    behaviour : {

      // Miliseconds delay between mousedown and drag start
      dragDelay : 100,

      // Miliseconds delay between mouseup and drag stop
      dragRevert : 100,

      // Determinme the opacity of Widget when start drag
      dragOpacity : 0.8,

      // Cookies (require Cookie plugin) to store positions and states
      useCookies : false
    },

    // Some effects that can be apply sometimes
    effects : {

      // Miliseconds for effects duration
      effectDuration : 500,

      // Can be none, slide or fade
      widgetShow : 'none',
      widgetHide : 'none',
      widgetClose : 'none',
      widgetExtend : 'none',
      widgetCollapse : 'none',
      widgetOpenEdit : 'none',
      widgetCloseEdit : 'none',
      widgetCancelEdit : 'none'
    },

    // Only for the optional cookie feature
    cookies : {

      // Cookie path
      path : '',

      // Cookie domain
      domain : '',

      // Cookie expiration time in days
      expires : 90,

      // Store a secure cookie?
      secure : false,

      // Cookie name for close Widgets
      closeName : 'ew-close',

      // Cookie name for disable all Widgets
      disableName : 'ew-disable',

      // Cookie name for positined Widgets
      positionName : 'ew-position',

      // Cookie name for collapsed Widgets
      collapseName : 'ew-collapse'
    },

    // Options name to use in the HTML markup
    options : {

      // To recognize a movable Widget
      movable : 'movable',

      // To recognize a editable Widget
      editable : 'editable',

      // To recognize a collapse Widget
      collapse : 'collapse',

      // To recognize a removable Widget
      removable : 'removable',

      // To recognize a collapsable Widget
      collapsable : 'collapsable',

      // To recognize Widget that require confirmation when remove
      closeConfirm : 'closeconfirm'
    },

    // Callbacks functions
    callbacks : {

      // When a Widget is added on demand, send the widget object and place ID
      onAdd : null,

      // When a editbox is closed, send the link and the widget objects
      onEdit : null,

      // When a Widget is show, send the widget object
      onShow : null,

      // When a Widget is hide, send the widget object
      onHide : null,

      // When a Widget is closed, send the link and the widget objects
      onClose : null,

      // When Widgets are enabled using the appropiate public method
      onEnable : null,

      // When a Widget is extend, send the link and the widget objects
      onExtend : null,

      // When Widgets are disabled using the appropiate public method
      onDisable : null,

      // When a editbox is closed, send a ui object, see jQuery::sortable()
      onDragStop : null,

      // When a Widget is collapse, send the link and the widget objects
      onCollapse : null,

      // When a Widget is try to added, send the widget object and place ID
      onAddQuery : null,

      // When a editbox is try to close, send the link and the widget objects
      onEditQuery : null,

      // When a Widget is try to show, send the widget object
      onShowQuery : null,

      // When a Widget is try to hide, send the widget object
      onHideQuery : null,

      // When a Widget is try to close, send the link and the widget objects
      onCloseQuery : null,

      // When a editbox is cancel (close), send the link and the widget objects
      onCancelEdit : null,

      // When Widgets are enabled using the appropiate public method
      onEnableQuery : null,

      // When a Widget is try to expand, send the link and the widget objects
      onExtendQuery : null,

      // When Widgets are disabled using the appropiate public method
      onDisableQuery : null,

      // When a Widget is try to expand, send the link and the widget objects
      onCollapseQuery : null,

      // When a editbox is try to cancel, send the link and the widget objects
      onCancelEditQuery : null,

      // When one Widget is repositioned, send the positions serialization
      onChangePositions : null,

      // When Widgets need repositioned, get the serialization positions
      onRefreshPositions : null
    },

    // Selectors in HTML markup. All can be change by you, but not all is
    // used in the HTML markup. For example, the "editLink" or "closeLink"
    // is prepared by the plugin for every Widget.
    selectors : {

      // Container of a Widget (into another element that use as place)
      // The container can be "div" or "li", for example. In the first case
      // use another "div" as place, and a "ul" in the case of "li".
      container : 'div',

      // Class identifier for a Widget
      widget : '.p',

      // Class identifier for a Widget place (parents of Widgets)
      places : '.p-place',

      // Class identifier for a Widget header (handle)
      header : '.tab',

      // Class for the Widget header menu
      widgetMenu : '.widget-menu',

      // Class identifier for Widget editboxes
      editbox : '.widget-editbox',

      // Class identifier for Widget content
      content : '.widget-content',

      // Class identifier for editbox close link or button, for example
      closeEdit : '.widget-close-editbox',

      // Class identifier for a Widget edit link
      editLink : '.widget-editlink',

      // Class identifier for a Widget close link
      closeLink : '.widget-closelink',

      // Class identifier for Widgets placehoders
      placeHolder : '.p-place',

      // Class identifier for a Widget collapse link
      collapseLink : '.widget-collapselink'
    },

    // To be translate the plugin into another languages
    // But this variables can be used to show images instead
    // links text, if you preffer. In this case set the HTML
    // of the IMG elements.
    i18n : {

      // Widget edit link text
      editText : 'Edit',

      // Widget close link text
      closeText : 'Close',

      // Widget extend link text
      extendText : 'Extend',

      // Widget collapse link text
      collapseText : 'Collapse',

      // Widget cancel edit link text
      cancelEditText : 'Cancel',

      // Widget edition link title
      editTitle : 'Edit this widget',

      // Widget close link title
      closeTitle : 'Close this widget',

      // Widget confirmation dialog message
      confirmMsg : 'Remove this widget?',

      // Widget cancel edit link title
      cancelEditTitle : 'Cancel edition',

      // Widget extend link title
      extendTitle : 'Extend this widget',

      // Widget collapse link title
      collapseTitle : 'Collapse this widget'
    }
  };

  //////////////////////////////
  // Private plugin functions //
  //////////////////////////////
  
  /**
   * Initialize the widgets
   *
   * This private function is used in two methods of the plugin, the main
   * public method: EasyWidgets() and AddEasyWidget() public method. In other
   * words, this function is the main function of the plugin, and is use to
   * initialize the widgets at a first time, and initialize the widgets added
   * on demand.
   *
   * This function separate different things into other private functions:
   * for more details see the related and used here plugin private functions.
   *
   * @access private
   * @param settings Array with the plugin settings
   * @param widgetOnDemand Boolean Widget added on demand or not
   * @return Boolean True in every case
   *
   */
  function InitializeWidgets(
   settings, widgetOnDemand){
     var b = widgetOnDemand;
     var d = $.fn.EasyWidgets.defaults;
     var s = $.extend(true, d, settings);
     $(s.selectors.widget).each(function(){
       PrepareWidgetBehaviour($(this),b,s);
     });
     RepositionedWidgets(s);
     MakeWidgetsSortables(s);
     CleanWidgetsCookies(s,b);
     return true;
  }

  /**
   * Prepare the widgets behaviour
   *
   * This private function is called from another: InitializeWidgets()
   * to prepare the behaviour of a found widget: append the widget menu
   * if is needed, put into this the appropiate links, etc.
   *
   * As you can see, another private plugin functions are used here,
   * we refer you to this functions for more details about this task.
   * However, here is an important question about this function logical:
   *
   * This function can be use to deal with "normal" widgets and widgets
   * added on demand. This function can be called to prepare certain
   * widget that as been prepared when page onload: so, this widgets
   * cannot be prepared again.
   *
   * To evit the duplication of the widget menus, basically, we find
   * for this widget menu, and, if is empty, this widget need to be
   * prepared, but, if this widget have a menu yet, cannot need to
   * be prepared.
   *
   * This condition only have sense when added widgets on demand, if
   * not is the case, no one widget have a menu before prepared, so,
   * are prepared here the first time that this function is called.
   *
   * @access private
   * @see InitializeWidgets()
   * @see AddWidgetEditLink()
   * @see AddWidgetRemoveLink()
   * @see AddWidgetCollapseLink()
   * @param widget jQuery object with a widget
   * @param widgetOnDemand Boolean Widget added on demand or not
   * @param settings Array with the plugin settings
   * @return Boolean True if widget are prepared, False if is yet prepared
   *
   */
  function PrepareWidgetBehaviour(widget, widgetOnDemand, settings){
    var s = settings;
    var widgetMenu = widget.find(s.selectors.widgetMenu);
    if(widgetMenu.html() == null){
      var widgetId = widget.attr('id');
      var haveId = ($.trim(widgetId) != '');
      widget.find(s.selectors.editbox).hide();
      if(widgetOnDemand && haveId && s.behaviour.useCookies){
        // Force this widget out of closed widgets cookie
        // because in other case is possible that widget
        // are added, but in fact not show in the document
        CleanCookie(widgetId, s.cookies.closeName, s);
      }
      if(!widgetOnDemand && haveId && s.behaviour.useCookies
       && GetCookie(s.cookies.closeName) != null){
         var cookieValue = GetCookie(s.cookies.closeName);
         if(cookieValue.indexOf(widgetId) != -1){
           // But in case of not on demand widget, is possible
           // to hide the widget, if is present in the appropiate
           // related cookie
           widget.hide();
         }
      }
      var menuWrap = '<span class="' + s.selectors
       .widgetMenu.replace(/\./, '') + '"></span>';
      widget.find(s.selectors.header).append(menuWrap);
      // Now this menu is a valid wrap to add the links
      widgetMenu = widget.find(s.selectors.widgetMenu);
      // The order of this function call is important
      // because determine the order of links appear
      AddWidgetCollapseLink(widget, widgetMenu, s);
      AddWidgetEditLink(widget, widgetMenu, s);
      AddWidgetRemoveLink(widget, widgetMenu, s);
      return true;
    }else{
      return false;
    }
  }

  /**
   * Repositioned the widgets
   *
   * This private function is called from InitializeWidgets() and is used
   * to repositioned the widgets in the appropiate places into the document.
   *
   * Some important question about this function is that the plugin can
   * repositioned the widgets follow certain string, that containt the
   * needed information.
   *
   * This string is produced in WidgetsPositionsChange() private function,
   * and bassically contain the places IDs and the widgets IDs saved in
   * a know format, that here we read to apply just later.
   *
   * Take a look at this: the mentioned string is saved in a cookie if you
   * use the cookies feature of the plugin. But in any case the plugin send
   * to you this string in the "onChangePositions()" callback.
   *
   * What is this? Suppose that you cannot use cookies, but still want to
   * repositioned the widgets. So, you can get the refered string and save
   * it in a database, for example.
   *
   * Then, just when this function is executed, you can provide this string
   * returning it in the "onRefreshPositions()" plugin callback. Then, if you
   * provide here a string that contain the widgets positions, the plugin use
   * this string to repositioned the widgets.
   *
   * If you use the cookies plugin feature, the widget read the appropiate
   * cookie, get the string previously saved (see WidgetsPositionsChange())
   * and repositioned the widgets. Of course, if you not provide any string
   * and also not use the cookies feature, the widgets cannot be positioned.
   *
   * Another thing more. You can see at WidgetsPositionsChange() how we
   * conform the appropiate string, so, in this function we read the string
   * based on the appropiate format. This string is like this:
   *
   * place-1=widget-1,widget-2|place-1=widget-3,widget-4
   *
   * Note one more thing: the order of the string is not casual: reflect the
   * real order of the places and widgets in the document when the string is
   * formed, so, the order of the widgets after this function is executed is
   * the correct, because we follow the string as is.
   *
   * @access private
   * @see InitializeWidgets()
   * @see PrepareSortablePlaces()
   * @see WidgetsPositionsChange()
   * @return Boolean True in every case
   * 
   */
  function RepositionedWidgets(settings){
    var s = settings;
    var positions = '';
    if($.isFunction(s.callbacks.onRefreshPositions)){
      positions = s.callbacks.onRefreshPositions();
    }
    // Only if not provide a string widget positions,
    // use cookies and the appropiate cookie is not empty
    if(($.trim(positions) == '') && s.behaviour.useCookies
     && GetCookie(s.cookies.positionName) != null){
       // We get the widgets positions from the cookie
       positions = GetCookie(s.cookies.positionName)
    }
    if($.trim(positions) != ''){
      // Get the widgets places IDs and widgets IDs
      var places = positions.split('|');
      var totalPlaces = places.length;
      for(var i = 0; i < totalPlaces; i++){
        // Every part contain a place ID and possible widgets IDs
        var place = places[i].split('=');
        // Validate (more or less) the format of the part that must
        // contain two element: A place ID and one or more widgets IDs
        if(place.length == 2){
          // Subpart one: the place ID
          var placeSel = '#'+place[0];
          // Subpart two: one or more widgets IDs
          var widgets = place[1].split(',');
          var totalWidgets = widgets.length;
          // Here we have a place and one or more widgets IDs
          for(var j = 0; j < totalWidgets; j++){
            if($.trim(widgets[j]) != ''){
              // So, append every widget in the appropiate place
              var widgetSel = '#'+widgets[j];
              $(widgetSel).appendTo(placeSel);
            }
          }
        }
      }
    }
    return true;
  }

  /**
   * Make widgets sortables
   *
   * This private function make found widgets as sortable items. This
   * is called from another plugin private funtion: InitializeWidgets()
   *
   * As you can see, another private plugin functions are used here:
   * we refer you to this functions for more details about this task.
   *
   * @access private
   * @see InitializeWidgets()
   * @see GetSortableItems()
   * @see PrepareSortableHeaders()
   * @see PrepareSortablePlaces()
   * @param settings Array with the plugin settings
   * @return Boolean True in every case
   * 
   */
  function MakeWidgetsSortables(settings){
    var sortables = GetSortableItems(settings);
    PrepareSortableHeaders(sortables, settings);
    PrepareSortablePlaces(sortables, settings);
    return true;
  }

  /**
   * Find widgets and places as sortables items
   *
   * And return it. This function is called from MakeWidgetsSortables()
   * to find the widgets and places as sortable items to work with this.
   *
   * @access private
   * @see MakeWidgetsSortables()
   * @param settings Array with the plugin settings
   * @return Boolean True in every case
   *
   */
  function GetSortableItems(settings){
    var fixesSel = '';
    var s = settings;
    // Iterate all the widgets in document
    $(s.selectors.widget).each(function(count){
      // When found a not movable widget
      if(!$(this).hasClass(s.options.movable)){
        // Try to get the widget ID
        if(!this.id){
          // And if not found prepare a special one
          this.id = 'fixed-widget-id-' + count;
        }
        // Because this widget (fixed) not can be
        // put as a sortable item, so, add to the
        // fixed widgets selector, to use bellow
        if(fixesSel == ''){
          fixesSel += '#'+this.id;
        }else{
          fixesSel += ',' + '#'+this.id;
        }
      }
    });
    // We prepare now the widget that cannot be put as
    // sortable items, because are fixed widgets. We cannot
    // use directly the fixed widgets selectors, because is
    // no one fixed widget is found the selector is like this:
    // :not(), that is, a emtpy "not selector", and this cause
    // problems with jQuery version 1.3
    var notFixes = '';
    if($.trim(fixesSel) == ''){
      // So, if no fixed widgets are found, dont use the not selector
      notFixes = '> '+s.selectors.container;
    }else{
      // Use only in case that one or more fixed widgets are found
      notFixes = '> '+s.selectors.container+':not(' + fixesSel + ')';
    }
    // Its all. Return not fixed widgets and places as sortable items
    return $(notFixes, s.selectors.places);
  }

  /**
   * Prepare sortables widgets headers
   *
   * This private function is called from another: MakeWidgetsSortables()
   * and is used to prepare the widget headers as sortable items. Some
   * behaviour is needed here, and the mayor part is based in the sortable
   * feature of the jQuery UI library.
   *
   * In other words, this function prepare the widgets sortable headers
   * to can be use as the widget handle, that the users can be use to move
   * the widget into one place to another.
   *
   * For more information we refer you to the jQuery UI sortable feature
   * documentation at this website for example: <http://www.api.jquery.com/>
   *
   * @access private
   * @see MakeWidgetsSortables()
   * @param sortableItems jQuery object with found sortable items
   * @param settings Array with the plugin settings
   * @return Boolean True in every case
   *
   */
  function PrepareSortableHeaders(sortableItems, settings){
    var s = settings;
    sortableItems.find(s.selectors.header).css({
      cursor: 'move'
    }).mousedown(function(e){
      var header = $(this);
      var widget = header.parent();
      sortableItems.css({width:''});
      widget.css({
        width: widget.width() + 'px'
      });
    }).mouseup(function(){
      var header = $(this);
      var widget = header.parent();
      if(!widget.hasClass('dragging')){
        widget.css({width:''});
      }else{
        $(s.selectors.places).sortable('disable');
      }
    });
    return true;
  }

  /**
   * Prepare sortables widgets places
   *
   * This private function is called from another: MakeWidgetsSortables()
   * and is used to prepare the widget places as sortable items. Some
   * behaviour is needed here, and the mayor part is based in the sortable
   * feature of the jQuery UI library.
   *
   * For more information we refer you to the jQuery UI sortable feature
   * documentation at this website for example: <http://www.api.jquery.com/>
   *
   * @access private
   * @see MakeWidgetsSortables()
   * @see WidgetsPositionsChange()
   * @param sortableItems jQuery object with found sortable items
   * @param settings Array with the plugin settings
   * @return Boolean True in every case
   *
   */
  function PrepareSortablePlaces(sortableItems, settings){
    var s = settings;
    $(s.selectors.places).sortable('destroy');
    $(s.selectors.places).sortable({
      items: sortableItems,
      containment: 'document',
      forcePlaceholderSize: true,
      handle: s.selectors.header,
      delay: s.behaviour.dragDelay,
      revert: s.behaviour.dragRevert,
      opacity: s.behaviour.dragOpacity,
      connectWith: $(s.selectors.places),
      placeholder: s.selectors.placeHolder,
      start : function(e, ui){
        $(ui.helper).addClass('dragging');
        return true;
      },
      stop : function(e, ui){
        WidgetsPositionsChange(s);
        $(ui.item).css({width : ''});
        $(ui.item).removeClass('dragging');
        $(s.selectors.places).sortable('enable');
        if($.isFunction(s.callbacks.onDragStop)){
          s.callbacks.onDragStop(e, ui);
        }
        return true;
      }
    });
    // Ok, we take this place to disable widgets based on certain cookie
    if(s.behaviour.useCookies && (GetCookie(s.cookies.disableName) == 1)){
      $.fn.DisableEasyWidgets(s);
    }
    return true;
  }

  /**
   * Handle the widgets positions changes
   *
   * This function is called from the "stop" event of sortable widgets as
   * you can see here: PrepareSortablePlaces(), and is used to provide to
   * you of a string that contain the widgets positions in certain format.
   *
   * This string structure is like:
   *
   * place-1=widget-1,widget-2|place-1=widget-3,widget-4
   *
   * See bellow how we conform this. You can save this string in a database
   * for example, and provide latter, when the "onRefreshPositions()" callback
   * is executed. So, the plugin use this string to repositioned the widgets
   * as you can see in RepositionedWidgets() function.
   *
   * @access private
   * @see RepositionedWidgets()
   * @see PrepareSortablePlaces()
   * @param settings Array with the plugin settings
   * @return Boolean True in every case
   *
   */
  function WidgetsPositionsChange(settings){
    var s = settings;
    var positions = '';
    $(s.selectors.places).each(function(){
      var widgets = '';
      var place = $(this);
      var places = place.attr('id') + '=';
      place.children(s.selectors.widget).each(function(){
        var widget = this;
        var widgetId = widget.id;
        var haveId = ($.trim(widgetId) != '');
        if(haveId){
          if(widgets == ''){
            widgets += widgetId;
          }else{
            widgets += ',' + widgetId;
          }
        }
      });
      places += widgets;
      if(positions == ''){
        positions += places;
      }else{
        positions += '|' + places;
      }
    });
    // You can save the positions string in a database, for example,
    // using the "onChangePositions()" plugin callback. So, when the
    // "onRefreshPositions()" callback is executed, you can retrieve
    // the string and returnt it: so the plugin use this string to
    // repositioned the widgets.
    if($.isFunction(s.callbacks.onChangePositions)){
      s.callbacks.onChangePositions(positions);
    }
    // @todo Maybe we only put the positions on the cookie
    // if the user font use the "onChangePositions()" callback, because
    // at this time, ever if no use the cookie value (the user provide)
    // the positions from "onRefreshPositions()" callback) the positions
    // are saved in the cookie...
    if(s.behaviour.useCookies){
      // However, you need to use the cookies feature
      // to make possible the widgets repositioned
      if(GetCookie(s.cookies.positionName) != positions){
        SetCookie(s.cookies.positionName, positions, s);
      }
    }
    return true;
  }

  /**
   * Prepare a widget collapse menu link
   *
   * @access private
   * @see PrepareWidgetBehaviour()
   * @param widget jQuery object with a widget encapsulation
   * @param widgetMenu jQuery object with a widget menu encapsulation
   * @param settings Array with the plugin settings
   * @return Boolean Truein every case
   *
   */
  function AddWidgetCollapseLink(widget, widgetMenu, settings){
    var s = settings;
    var link = '';
    var widgetId = widget.attr('id');
    var haveId = $.trim(widgetId) != '';
    var content = widget.find(s.selectors.content);
    if(widget.hasClass(s.options.collapsable)){
      if(widget.hasClass(s.options.collapse)){
        link = MenuLink(
          s.i18n.extendText,
          s.i18n.extendTitle,
          s.selectors.collapseLink
        );
        content.hide();
      }else{
        link = MenuLink(
          s.i18n.collapseText,
          s.i18n.collapseTitle,
          s.selectors.collapseLink
        );
      }
      if(haveId && s.behaviour.useCookies &&
       GetCookie(s.cookies.collapseName) != null){
         var cookieValue = GetCookie(s.cookies.collapseName);
         if(cookieValue.indexOf(widgetId) != -1){
           link = MenuLink(
             s.i18n.extendText,
             s.i18n.extendTitle,
             s.selectors.collapseLink
           );
           content.hide();
         }
      }
      $(link).mousedown(function(e){
        e.stopPropagation();
      }).click(function(){
        var canExtend = true;
        var canCollapse = true;
        var link = $(this);
        var widget = link.parents(s.selectors.widget);
        var widgetId = widget.attr('id');
        var haveId = $.trim(widgetId) != '';
        var content = widget.find(s.selectors.content);
        var contentVisible = content.css('display') != 'none';
        link.blur();
        if(contentVisible){
          if($.isFunction(s.callbacks.onCollapseQuery)){
            canCollapse = s.callbacks.onCollapseQuery(link,widget);
          }
          if(canCollapse){
            ApplyEffect(
              content,
              s.effects.widgetCollapse,
              s.effects.effectDuration,
              false
            );
            link.html(s.i18n.extendText);
            link.attr('title', s.i18n.extendTitle);
            if(s.behaviour.useCookies && widgetId){
              UpdateCookie(widgetId, s.cookies.collapseName, s);
            }
            if($.isFunction(s.callbacks.onCollapse)){
              s.callbacks.onCollapse(link, widget);
            }
          }
        }else{
          if($.isFunction(s.callbacks.onExtendQuery)){
            canExtend = s.callbacks.onExtendQuery(link, widget);
          }
          if(canExtend){
            link.html(s.i18n.collapseText);
            link.attr('title', s.i18n.collapseTitle);
            ApplyEffect(
              content,
              s.effects.widgetExtend,
              s.effects.effectDuration,
              true
            );
            if(haveId && s.behaviour.useCookies){
              CleanCookie(widgetId, s.cookies.collapseName, s);
            }
            if($.isFunction(s.callbacks.onExtend)){
              s.callbacks.onExtend(link, widget);
            }
          }
        }
        return false;
      }).appendTo(widgetMenu);
    }
    return true;
  }

  /**
   * Prepare a widget edit menu link
   *
   * @access private
   * @see PrepareWidgetBehaviour()
   * @param widget jQuery object with a widget encapsulation
   * @param widgetMenu jQuery object with a widget menu encapsulation
   * @param settings Array with the plugin settings
   * @return Boolean Truein every case
   *
   */
  function AddWidgetEditLink(widget, widgetMenu, settings){
    var s = settings;
    var link = '';
    if(widget.hasClass(s.options.editable)){
      link = MenuLink(
        s.i18n.editText,
        s.i18n.editTitle,
        s.selectors.editLink
      );
      widget.find(s.selectors.closeEdit).click(function(e){
        var link = $(this);
        var widget = link.parents(s.selectors.widget);
        var editbox = widget.find(s.selectors.editbox);
        var editLink = widget.find(s.selectors.editLink);
        link.blur();
        ApplyEffect(
          editbox,
          s.effects.widgetCloseEdit,
          s.effects.effectDuration,
          false
        );
        editLink.html(s.i18n.editText);
        editLink.attr('title', s.i18n.editTitle);
        return false;
      });
      $(link).mousedown(function(e){
        e.stopPropagation();
      }).click(function(){
        var link = $(this);
        var canShow = canHide = true;
        var widget = link.parents(s.selectors.widget);
        var editbox = widget.find(s.selectors.editbox);
        var editboxVisible = editbox.css('display') != 'none';
        link.blur();
        if(editboxVisible){
          if($.isFunction(s.callbacks.onCancelEditQuery)){
            canHide = s.callbacks.onCancelEditQuery(link, widget);
          }
          if(canHide){
            ApplyEffect(
              editbox,
              s.effects.widgetCancelEdit,
              s.effects.effectDuration,
              false
            );
            link.html(s.i18n.editText);
            link.attr('title', s.i18n.editTitle);
            if($.isFunction(s.callbacks.onCancelEdit)){
              s.callbacks.onCancelEdit(link, widget);
            }
          }
        }else{
          if($.isFunction(s.callbacks.onEditQuery)){
            canShow = s.callbacks.onEditQuery(link, widget);
          }
          if(canShow){
            link.html(s.i18n.cancelEditText);
            link.attr('title', s.i18n.cancelEditTitle);
            ApplyEffect(
              editbox,
              s.effects.widgetOpenEdit,
              s.effects.effectDuration,
              true
            );
            if($.isFunction(s.callbacks.onEdit)){
              s.callbacks.onEdit(link, widget);
            }
          }
        }
        return false;
      }).appendTo(widgetMenu);
    }
    return true;
  }
  
  /**
   * Prepare a widget remove menu link
   *
   * @access private
   * @see PrepareWidgetBehaviour()
   * @param widget jQuery object with a widget encapsulation
   * @param widgetMenu jQuery object with a widget menu encapsulation
   * @param settings Array with the plugin settings
   * @return Boolean Truein every case
   *
   */
  function AddWidgetRemoveLink(widget, widgetMenu, settings){
    var s = settings;
    var link = '';
    if(widget.hasClass(s.options.removable)){
      link = MenuLink(
        s.i18n.closeText,
        s.i18n.closeTitle,
        s.selectors.closeLink
      );
      $(link).mousedown(function(e){
        e.stopPropagation();
      }).click(function(){
        var link = $(this);
        var canRemove = true;
        var widget = link.parents(s.selectors.widget);
        var widgetId = widget.attr('id');
        var haveId = ($.trim(widgetId) != '');
        link.blur();
        if($.isFunction(s.callbacks.onCloseQuery)){
          canRemove = s.callbacks.onCloseQuery(link, widget);
        }
        if(canRemove){
          if(!widget.hasClass(s.options.closeConfirm)
            || confirm(s.i18n.confirmMsg)){
              if(haveId && s.behaviour.useCookies){
                UpdateCookie(widgetId, s.cookies.closeName, s);
              }
              ApplyEffect(
                widget,
                s.effects.widgetClose,
                s.effects.effectDuration,
                false
              );
              if($.isFunction(s.callbacks.onClose)){
                s.callbacks.onClose(link, widget);
              }
          }
        }
        return false;
      }).appendTo(widgetMenu);
    }
    return true;
  }

  /**
   * Clean widgets related cookies
   *
   * This private function is called from InitializeWidgets() and used to
   * clean certain widgets related cookies. What is this? Well, basically
   * here we find for no more used widgets IDs into the appropiate cookies
   * values, and remove from this.
   *
   * Why? Because in this form the related cookies ever still clean. ;)
   * This cookies are the "closed widgets" and "collapses widgets" cookies,
   * that store widgets IDs in the same way: separated by commas. So, find
   * widgets IDs that in fact not found in the document, and remove from the
   * appropiate cookie value, remainded the rest of the widgets IDs.
   *
   * Because this function is called from the main plugin method, called
   * itself every time that a page that contain widgets is refresh, or when
   * add widgets on demand, we only try to clean the cookies in a "random"
   * mode, because, finally, is not problem that a cookie contain widgets
   * IDs that dont exists.
   *
   * So, to save resources, we clean the cookies only in no on demand widgets,
   * and only in some "random" times, as you can see in the bellow code.
   *
   * @access private
   * @see InitializeWidgets()
   * @param settings Array with the plugin settings
   * @param widgetOnDemand Boolean Depend if deal with on demand widget or not
   * @return Boolean True in every case
   *
   */
  function CleanWidgetsCookies(settings, widgetOnDemand){
    var s = settings;
    var cleanCookies = !widgetOnDemand && s.behaviour.useCookies
      && (Math.ceil(Math.random() * 3) == 1);
    if(cleanCookies){
      var i = j = 0;
      var cookies = new Array(
        s.cookies.closeName,
        s.cookies.collapseName
      );
      var cookiesLen = cookies.length;
      var widgetsIds = new Array();
      $(s.selectors.widget).each(function(count){
        var widgetId = $(this).attr('id');
        if($.trim(widgetId) != ''){
          widgetsIds[count] = widgetId;
        }
      });
      for(i = 0; i < cookiesLen; i++){
        if(GetCookie(cookies[i])){
          var widgetId = '';
          var cleanValue = '';
          var storedValue = GetCookie(cookies[i]).split(',');
          var storedWidgets = storedValue.length;
          for(j = 0; j < storedWidgets; j++){
            widgetId = $.trim(storedValue[j]);
            if($.inArray(widgetId, widgetsIds) != -1){
              if($.trim(cleanValue) == ''){
                cleanValue += widgetId;
              }else{
                cleanValue += ','+widgetId;
              }
            }
          }
          SetCookie(cookies[i], cleanValue, s);
        }
      }
    }
    return true;
  }

  /**
   * Get a specific cookie value
   *
   * This function is based in jQuery Cookie plugin by Klaus Hartl
   *
   * @access private
   * @param name String with the cookie name
   * @return Null|String Cookie value or nothing
   *
   */
  function GetCookie(name){
    var result = null;
    if(document.cookie && $.trim(document.cookie) != ''){
      var cookies = document.cookie.split(';');
      var cookiesLen = cookies.length;
      if(cookiesLen > 0){
        for(var i = 0; i < cookiesLen; i++){
          var cookie = $.trim(cookies[i]);
          if (cookie.substring(0, name.length + 1) == (name + '=')){
            result = decodeURIComponent(cookie.substring(name.length + 1));
            break;
          }
        }
      }
    }
    return result;
  }

  /**
   * Set a specific cookie value
   *
   * This function is based in jQuery Cookie plugin by Klaus Hartl
   *
   * @access private
   * @param name String with the cookie name
   * @param value String with the cookie value
   * @param settings Array with plugin settings to use
   * @return Boolean True in every case
   *
   */
  function SetCookie(name, value, settings){
    var s = settings;
    var expires = '';
    var nType = 'number';
    if(s.cookies.expires && (typeof s.cookies.expires
     == nType) || s.cookies.expires.toUTCString){
       var date = null;
       if(typeof s.cookies.expires == nType){
         date = new Date();
         date.setTime(date.getTime() + (s.cookies.expires*24*60*60*1000));
       }else{
         date = s.cookies.expires;
       }
       // use expires attribute, max-age is not supported by IE
       expires = '; expires=' + date.toUTCString();
    }
    var path = s.cookies.path ? '; path=' + s.cookies.path : '';
    var domain = s.cookies.domain ? '; domain=' + s.cookies.domain : '';
    var secure = s.cookies.secure ? '; secure' : '';
    document.cookie = [name, '=', encodeURIComponent(value),
     expires, path, domain, secure].join('');
    return true;
  }

  /**
   * Clean a Widget Id from a cookie
   *
   * We use this in some places, so, centralize here. We clean certain
   * related cookie: two of the plugins related cookies using the same
   * structure to save their data, and can be clean in the same way.
   *
   * A string with comma separated Widgets IDs is stored in this cookies,
   * and "clean a cookie" want to say: remove certain Widget ID from this
   * cookie, because this widget is now visible or extended.
   *
   * @access private
   * @param widgetId String with a Widget identifier
   * @param cookieName String with the cookie name
   * @param settings Array with plugin settings to use
   * @return Boolean True in every case
   *
   */
  function CleanCookie(widgetId, cookieName, settings){
    var value = GetCookie(cookieName);
    if(value != null){
      if(value.indexOf(widgetId) != -1){
        value = value.replace(','+widgetId, '');
        value = value.replace(widgetId+',', '');
        value = value.replace(widgetId, '');
      }
      SetCookie(cookieName, value, settings);
    }
    return true;
  }

  /**
   * Update a Widget Id from a cookie
   *
   * We use this in some places, so, centralize here. We update certain
   * related cookie: two of the plugins related cookies using the same
   * structure to save their data, and can be update in the same way.
   *
   * A string with comma separated Widgets IDs is stored in this cookies,
   * and "update a cookie" want to say: put certain Widget ID in this
   * cookie, because this widget is now closed or collapsed.
   *
   * @access private
   * @param widgetId String with a Widget identifier
   * @param cookieName String with the cookie name
   * @param settings Array with plugin settings to use
   * @return Boolean True in every case
   *
   */
  function UpdateCookie(widgetId, cookieName, settings){
    var value = GetCookie(cookieName);
    if(value == null){
      value = widgetId;
    }else if(value.indexOf(widgetId) == -1){
      value = value+','+widgetId;
    }
    SetCookie(cookieName, value, settings);
    return true;
  }

  /**
   * Auxiliar function to prepare Widgets header menu links.
   *
   * @access private
   * @param text Link text
   * @param title Link title
   * @param aClass CSS class (behaviour) of link
   * @return String HTML of the link
   *
   */
  function MenuLink(text, title, aClass){
    var l = '<a href="#" title="TITLE" class="CLASS">TEXT</a>';
    l = l.replace(/TEXT/g, text);
    l = l.replace(/TITLE/g, title);
    l = l.replace(/CLASS/g, aClass.replace(/\./, ''));
    return l;
  }

  /**
   * Auxiliar function to show, hide and apply effects.
   *
   * @access private
   * @param jqObj jQuery object to apply the effect and show or hide
   * @param effect String that identifier what effect must be applied
   * @param duration Miliseconds to the effect duration
   * @param show Boolean True if want to show the object, False to be hide
   * @return Boolean True in every case
   *
   */
  function ApplyEffect(jqObj, effect, duration, show){
    var n = 'none', 
        f = 'fade',
        s = 'slide';
    if(!show){
      if(effect == n){
        jqObj.hide();
      }else if(effect == f){
        jqObj.fadeOut(duration);
      }else if(effect == s){
        jqObj.slideUp(duration);
      }
    }else{
      if(effect == n){
        jqObj.show();
      }else if(effect == f){
        jqObj.fadeIn(duration);
      }else if(effect == s){
        jqObj.slideDown(duration);
      }
    }
    return true;
  }
})(jQuery);

/* plugin */
jQuery.fn.dwFadingLinks = function(settings) {
	settings = jQuery.extend({
		color: '#ff8c00',
		duration: 500
	}, settings);
	return this.each(function() {
		var original = $(this).css('color');
		$(this).mouseover(function() { $(this).animate({ color: settings.color },settings.duration); });
		$(this).mouseout(function() { $(this).animate({ color: original },settings.duration); });
	});
};

/* usage */
$(document).ready(function() {
	$('.fade').dwFadingLinks({
		color: '#008000',
		duration: 700
	});
});
// jQuery Alert Dialogs Plugin
//
// Version 1.0
//
// Cory S.N. LaViska
// A Beautiful Site (http://abeautifulsite.net/)
// 29 December 2008
//
// Visit http://abeautifulsite.net/notebook/87 for more information
//
// Usage:
//        jAlert( message, [title, callback] )
//        jConfirm( message, [title, callback] )
//        jPrompt( message, [value, title, callback] )
// 
// History:
//
//        1.00 - Released (29 December 2008)
//
// License:
// 
//        This plugin is licensed under the GNU General Public License: http://www.gnu.org/licenses/gpl.html
//
(function($) {
    
    $.alerts = {
        
        // These properties can be read/written by accessing $.alerts.propertyName from your scripts at any time
        
        verticalOffset: -75,                // vertical offset of the dialog from center screen, in pixels
        horizontalOffset: 0,                // horizontal offset of the dialog from center screen, in pixels/
        repositionOnResize: true,           // re-centers the dialog on window resize
        overlayOpacity: .01,                // transparency level of overlay
        overlayColor: '#FFF',               // base color of overlay
        draggable: true,                    // make the dialogs draggable (requires UI Draggables plugin)
        okButton: '&nbsp;OK&nbsp;',         // text for the OK button
        cancelButton: '&nbsp;Cancel&nbsp;', // text for the Cancel button
        dialogClass: null,                  // if specified, this class will be applied to all dialogs
        
        // Public methods
        
        alert: function(type, message, title, callback) {
            if( title == null ) title = 'Alert';
            $.alerts._show(title, message, null, type, function(result) {
                if( callback ) callback(result);
            });
        },
        
        confirm: function(message, title, callback) {
            if( title == null ) title = 'Confirm';
            $.alerts._show(title, message, null, 'confirm', function(result) {
                if( callback ) callback(result);
            });
        },
            
        prompt: function(message, value, title, callback) {
            if( title == null ) title = 'Prompt';
            $.alerts._show(title, message, value, 'prompt', function(result) {
                if( callback ) callback(result);
            });
        },
        
        // Private methods
        
        _show: function(title, msg, value, type, callback) {
            
            $.alerts._hide();
            $.alerts._overlay('show');
            
            $("BODY").append(
              '<div id="popup_container">' +
                '<h1 id="popup_title"></h1>' +
                '<div id="popup_content">' +
                  '<div id="popup_message"></div>' +
                '</div>' +
              '</div>');
            
            if( $.alerts.dialogClass ) $("#popup_container").addClass($.alerts.dialogClass);
            
            // IE6 Fix
            var pos = ($.browser.msie && parseInt($.browser.version) <= 6 ) ? 'absolute' : 'fixed'; 
            
            $("#popup_container").css({
                position: pos,
                zIndex: 99999,
                padding: 0,
                margin: 0
            });
            
            $("#popup_title").text(title);
            $("#popup_content").addClass(type);
            $("#popup_message").text(msg);
            $("#popup_message").html( $("#popup_message").text().replace(/\n/g, '<br />') );
            
            $("#popup_container").css({
                minWidth: $("#popup_container").outerWidth(),
                maxWidth: $("#popup_container").outerWidth()
            });
            
            $.alerts._reposition();
            $.alerts._maintainPosition(true);

            switch (type) {
                case 'info':
                case 'warning':
                case 'success':
                case 'error':
                    $("#popup_message").after('<div id="popup_panel"><input type="button" value="' + $.alerts.okButton + '" id="popup_ok" /></div>');
                    $("#popup_ok").click( function() {
                        $.alerts._hide();
                        callback(true);
                    });
                    $("#popup_ok").focus().keypress( function(e) {
                        if( e.keyCode == 13 || e.keyCode == 27 ) $("#popup_ok").trigger('click');
                    });
                break;
                case 'confirm':
                    $("#popup_message").after('<div id="popup_panel"><input type="button" value="' + $.alerts.okButton + '" id="popup_ok" /> <input type="button" value="' + $.alerts.cancelButton + '" id="popup_cancel" /></div>');
                    $("#popup_ok").click( function() {
                        $.alerts._hide();
                        if( callback ) callback(true);
                    });
                    $("#popup_cancel").click( function() {
                        $.alerts._hide();
                        if( callback ) callback(false);
                    });
                    $("#popup_ok").focus();
                    $("#popup_ok, #popup_cancel").keypress( function(e) {
                        if( e.keyCode == 13 ) $("#popup_ok").trigger('click');
                        if( e.keyCode == 27 ) $("#popup_cancel").trigger('click');
                    });
                break;
                case 'prompt':
                    $("#popup_message").append('<br /><input type="text" size="30" id="popup_prompt" />').after('<div id="popup_panel"><input type="button" value="' + $.alerts.okButton + '" id="popup_ok" /> <input type="button" value="' + $.alerts.cancelButton + '" id="popup_cancel" /></div>');
                    $("#popup_prompt").width( $("#popup_message").width() );
                    $("#popup_ok").click( function() {
                        var val = $("#popup_prompt").val();
                        $.alerts._hide();
                        if( callback ) callback( val );
                    });
                    $("#popup_cancel").click( function() {
                        $.alerts._hide();
                        if( callback ) callback( null );
                    });
                    $("#popup_prompt, #popup_ok, #popup_cancel").keypress( function(e) {
                        if( e.keyCode == 13 ) $("#popup_ok").trigger('click');
                        if( e.keyCode == 27 ) $("#popup_cancel").trigger('click');
                    });
                    if( value ) $("#popup_prompt").val(value);
                    $("#popup_prompt").focus().select();
                break;
            }
            
            // Make draggable
            if( $.alerts.draggable ) {
                try {
                    $("#popup_container").draggable({ handle: $("#popup_title") });
                    $("#popup_title").css({ cursor: 'move' });
                } catch(e) { /* requires jQuery UI draggables */ }
            }
        },
        
        _hide: function() {
            $("#popup_container").remove();
            $.alerts._overlay('hide');
            $.alerts._maintainPosition(false);
        },
        
        _overlay: function(status) {
            switch( status ) {
                case 'show':
                    $.alerts._overlay('hide');
                    $("BODY").append('<div id="popup_overlay"></div>');
                    $("#popup_overlay").css({
                        position: 'absolute',
                        zIndex: 99998,
                        top: '0px',
                        left: '0px',
                        width: '100%',
                        height: $(window).height() + 'px',
                        background: $.alerts.overlayColor,
                        opacity: $.alerts.overlayOpacity
                    });
                break;
                case 'hide':
                    $("#popup_overlay").remove();
                break;
            }
        },
        
        _reposition: function() {
            var top = (($(window).height() / 2) - ($("#popup_container").outerHeight() / 2)) + $.alerts.verticalOffset;
            var left = (($(window).width() / 2) - ($("#popup_container").outerWidth() / 2)) + $.alerts.horizontalOffset;
            if( top < 0 ) top = 0;
            if( left < 0 ) left = 0;
            
            // IE6 fix
            if( $.browser.msie && parseInt($.browser.version) <= 6 ) top = top + $(window).scrollTop();
            
            $("#popup_container").css({
                top: top + 'px',
                left: left + 'px'
            });
            $("#popup_overlay").height( $(document).height() );
        },
        
        _maintainPosition: function(status) {
            if( $.alerts.repositionOnResize ) {
                switch(status) {
                    case true:
                        $(window).bind('resize', function() {
                            $.alerts._reposition();
                        });
                    break;
                    case false:
                        $(window).unbind('resize');
                    break;
                }
            }
        }
        
    }
    
    // Shortuct functions
    jAlert = function(type, message, title, callback) {
        $.alerts.alert(type, message, title, callback);
    }
    
    jConfirm = function(message, title, callback) {
        $.alerts.confirm(message, title, callback);
    };
        
    jPrompt = function(message, value, title, callback) {
        $.alerts.prompt(message, value, title, callback);
    };
    
})(jQuery);


	


			$(document).ready(function(){
				
				

				$('.boxgrid.caption').hover(function(){
					$(".cover", this).stop().animate({top:'0px'},{queue:false,duration:180});
				}, function() {
					$(".cover", this).stop().animate({top:'120px'},{queue:false,duration:120});
				});
			});
			
			
			
			//galeriq
			
			
			$(document).ready(
				function (){
					$("#pikame").PikaChoose();
				});
				
			$(document).ready(
				function (){
					$("#pikame_user").PikaChoose({user_thumbs:true, show_prev_next:false});
			});
			
			$(document).ready(
				function (){
					$("#pikame_compact").PikaChoose({user_thumbs:true, show_prev_next:false});
			});
			
			

/*** Dynamic Tabs ***/
///  By Muhsin Meydan: any questions send to meydan1@hotmail.com ///
///  Leave this line as reference       ///

   $(function () {  
             // Display the first tab content
            // Set the first tab as start tab onload: if you want to set no start tab comment it.
            DisplayTabContent(0);
            
                // get index of the clicked navigation item in the list
                $("ul.tabslist li a" ).click(function(){
                
                    // if animation has finished: meaning size()==0 then allow for other clicks
                    if ($('div.tabscontent_container > div.tabcontent:animated').size() == 0)
                    {
                        $("ul.tabslist li").removeClass('current');
                        var $listItem = $(this).parent().addClass('current');//set as current class

                        var index = $("ul.tabslist li ").index($listItem);// get index 

                        if( index > -1 ){
                        DisplayTabContent(index);
                        }
                    }
                });
                 return false;   
         });

    /**Display tab content that was clicked by index and hide the rest**/
    function DisplayTabContent(index) {
        // display the first tab content
        // $("div.tabscontent_container > div.tabcontent").hide().filter(":nth("+index+")").html("asdadasdada" + index);
        if(index != "0") {
            $("div.tabscontent_container > div.tabcontent").hide()
            $("#loading").show();
            $.get("scr/ajax.php", { tt: "lastadded", id: index },
            function(data){
            $("div.tabscontent_container > div.tabcontent").filter(":nth("+index+")").html(data);
            $("div.tabscontent_container > div.tabcontent").filter(":nth("+index+")").fadeIn('slow');
            return false;
            });
        }
            $("div.tabscontent_container > div.tabcontent").hide().filter(":nth("+index+")").fadeIn('slow');
            return false;
    }
	
	
	
	
	


/*
 * Tooltip script 
 * powered by jQuery (http://www.jquery.com)
 * 
 * written by Alen Grakalic (http://cssglobe.com)
 * 
 * for more info visit http://cssglobe.com/post/1695/easiest-tooltip-and-image-preview-using-jquery
 *
 */
 


this.tooltip = function(){	
	/* CONFIG */		
		xOffset = 10;
		yOffset = 20;		
		// these 2 variable determine popup's distance from the cursor
		// you might want to adjust to get the right result		
	/* END CONFIG */		
	$("a.tooltip").hover(function(e){											  
		this.t = this.title;
		this.title = "";									  
		$("body").append("<p id='tooltip'>"+ this.t +"</p>");
		$("#tooltip")
			.css("top",(e.pageY - xOffset) + "px")
			.css("left",(e.pageX + yOffset) + "px")
			.fadeIn("fast");		
    },
	function(){
		this.title = this.t;		
		$("#tooltip").remove();
    });	
	$("a.tooltip").mousemove(function(e){
		$("#tooltip")
			.css("top",(e.pageY - xOffset) + "px")
			.css("left",(e.pageX + yOffset) + "px");
	});			
};



// starting the script on page load
$(document).ready(function(){
	tooltip();
});

function findValue(li) {
    if( li == null ) return alert("No match!");

    // if coming from an AJAX call, let's use the CityId as the value
    if( !!li.extra ) var sValue = li.extra[0];

    // otherwise, let's just display the value in the text box
    else var sValue = li.selectValue;
}

function selectItem(li) {
    findValue(li);
}

function formatItem(row) {
    return row[0];
}

function lookupAjax(){
    var oSuggest = $("#CityAjax")[0].autocompleter;

    oSuggest.findValue();

    return false;
}

function lookupLocal(){
    var oSuggest = $("#other_author")[0].autocompleter;

    oSuggest.findValue();

    return false;
}

$(document).ready(function() {
    $("#other_author").autocomplete(
        "http://livetrance.net/scr/ajax.php",
        {
            delay:10,
            minChars:3,
            matchSubset:0,
            matchContains:1,
            cacheLength:10,
            width:250,
            onItemSelect:selectItem,
            onFindValue:findValue,
            formatItem:formatItem,
            autoFill:true
        }
    );
});

