/*
 * jQuery Form Plugin
 * version: 2.16 (17-OCT-2008)
 * @requires jQuery v1.2.2 or later
 *
 * Examples and documentation at: http://malsup.com/jquery/form/
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Revision: $Id$
 */
;(function($) {

/*
    Usage Note:  
    -----------
    Do not use both ajaxSubmit and ajaxForm on the same form.  These
    functions are intended to be exclusive.  Use ajaxSubmit if you want
    to bind your own submit handler to the form.  For example,

    $(document).ready(function() {
        $('#myForm').bind('submit', function() {
            $(this).ajaxSubmit({
                target: '#output'
            });
            return false; // <-- important!
        });
    });

    Use ajaxForm when you want the plugin to manage all the event binding
    for you.  For example,

    $(document).ready(function() {
        $('#myForm').ajaxForm({
            target: '#output'
        });
    });
        
    When using ajaxForm, the ajaxSubmit function will be invoked for you
    at the appropriate time.  
*/

/**
 * ajaxSubmit() provides a mechanism for immediately submitting 
 * an HTML form using AJAX.
 */
$.fn.ajaxSubmit = function(options) {
    // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
    if (!this.length) {
        log('ajaxSubmit: skipping submit process - no element selected');
        return this;
    }

    if (typeof options == 'function')
        options = { success: options };

    options = $.extend({
        url:  this.attr('action') || window.location.toString(),
        type: this.attr('method') || 'GET'
    }, options || {});

    // hook for manipulating the form data before it is extracted;
    // convenient for use with rich editors like tinyMCE or FCKEditor
    var veto = {};
    this.trigger('form-pre-serialize', [this, options, veto]);
    if (veto.veto) {
        log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
        return this;
   }

    var a = this.formToArray(options.semantic);
    if (options.data) {
        options.extraData = options.data;
        for (var n in options.data) {
          if(options.data[n] instanceof Array) {
            for (var k in options.data[n])
              a.push( { name: n, value: options.data[n][k] } )
          }  
          else
             a.push( { name: n, value: options.data[n] } );
        }
    }

    // give pre-submit callback an opportunity to abort the submit
    if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
        log('ajaxSubmit: submit aborted via beforeSubmit callback');
        return this;
    }    

    // fire vetoable 'validate' event
    this.trigger('form-submit-validate', [a, this, options, veto]);
    if (veto.veto) {
        log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
        return this;
    }    

    var q = $.param(a);

    if (options.type.toUpperCase() == 'GET') {
        options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
        options.data = null;  // data is null for 'get'
    }
    else
        options.data = q; // data is the query string for 'post'

    var $form = this, callbacks = [];
    if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
    if (options.clearForm) callbacks.push(function() { $form.clearForm(); });

    // perform a load on the target only if dataType is not provided
    if (!options.dataType && options.target) {
        var oldSuccess = options.success || function(){};
        callbacks.push(function(data) {
            $(options.target).html(data).each(oldSuccess, arguments);
        });
    }
    else if (options.success)
        callbacks.push(options.success);

    options.success = function(data, status) {
        for (var i=0, max=callbacks.length; i < max; i++)
            callbacks[i].apply(options, [data, status, $form]);
    };

    // are there files to upload?
    var files = $('input:file', this).fieldValue();
    var found = false;
    for (var j=0; j < files.length; j++)
        if (files[j])
            found = true;

    // options.iframe allows user to force iframe mode
   if (options.iframe || found) { 
       // hack to fix Safari hang (thanks to Tim Molendijk for this)
       // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
       if ($.browser.safari && options.closeKeepAlive)
           $.get(options.closeKeepAlive, fileUpload);
       else
           fileUpload();
       }
   else
       $.ajax(options);

    // fire 'notify' event
    this.trigger('form-submit-notify', [this, options]);
    return this;


    // private function for handling file uploads (hat tip to YAHOO!)
    function fileUpload() {
        var form = $form[0];
        
        if ($(':input[@name=submit]', form).length) {
            alert('Error: Form elements must not be named "submit".');
            return;
        }
        
        var opts = $.extend({}, $.ajaxSettings, options);
		var s = jQuery.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts);

        var id = 'jqFormIO' + (new Date().getTime());
        var $io = $('<iframe id="' + id + '" name="' + id + '" />');
        var io = $io[0];

        if ($.browser.msie || $.browser.opera) 
            io.src = 'javascript:false;document.write("");';
        $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });

        var xhr = { // mock object
            aborted: 0,
            responseText: null,
            responseXML: null,
            status: 0,
            statusText: 'n/a',
            getAllResponseHeaders: function() {},
            getResponseHeader: function() {},
            setRequestHeader: function() {},
            abort: function() { 
                this.aborted = 1; 
                $io.attr('src','about:blank'); // abort op in progress
            }
        };

        var g = opts.global;
        // trigger ajax global events so that activity/block indicators work like normal
        if (g && ! $.active++) $.event.trigger("ajaxStart");
        if (g) $.event.trigger("ajaxSend", [xhr, opts]);

		if (s.beforeSend && s.beforeSend(xhr, s) === false) {
			s.global && jQuery.active--;
			return;
        }
        if (xhr.aborted)
            return;
        
        var cbInvoked = 0;
        var timedOut = 0;

        // add submitting element to data if we know it
        var sub = form.clk;
        if (sub) {
            var n = sub.name;
            if (n && !sub.disabled) {
                options.extraData = options.extraData || {};
                options.extraData[n] = sub.value;
                if (sub.type == "image") {
                    options.extraData[name+'.x'] = form.clk_x;
                    options.extraData[name+'.y'] = form.clk_y;
                }
            }
        }

        // take a breath so that pending repaints get some cpu time before the upload starts
        setTimeout(function() {
            // make sure form attrs are set
            var t = $form.attr('target'), a = $form.attr('action');
            $form.attr({
                target:   id,
                method:   'POST',
                action:   opts.url
            });
            
            // ie borks in some cases when setting encoding
            if (! options.skipEncodingOverride) {
                $form.attr({
                    encoding: 'multipart/form-data',
                    enctype:  'multipart/form-data'
                });
            }

            // support timout
            if (opts.timeout)
                setTimeout(function() { timedOut = true; cb(); }, opts.timeout);

            // add "extra" data to form if provided in options
            var extraInputs = [];
            try {
                if (options.extraData)
                    for (var n in options.extraData)
                        extraInputs.push(
                            $('<input type="hidden" name="'+n+'" value="'+options.extraData[n]+'" />')
                                .appendTo(form)[0]);
            
                // add iframe to doc and submit the form
                $io.appendTo('body');
                io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
                form.submit();
            }
            finally {
                // reset attrs and remove "extra" input elements
                $form.attr('action', a);
                t ? $form.attr('target', t) : $form.removeAttr('target');
                $(extraInputs).remove();
            }
        }, 10);

        function cb() {
            if (cbInvoked++) return;
            
            io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);

            var operaHack = 0;
            var ok = true;
            try {
                if (timedOut) throw 'timeout';
                // extract the server response from the iframe
                var data, doc;

                doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
                
                if (doc.body == null && !operaHack && $.browser.opera) {
                    // In Opera 9.2.x the iframe DOM is not always traversable when
                    // the onload callback fires so we give Opera 100ms to right itself
                    operaHack = 1;
                    cbInvoked--;
                    setTimeout(cb, 100);
                    return;
                }
                
                xhr.responseText = doc.body ? doc.body.innerHTML : null;
                xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
                xhr.getResponseHeader = function(header){
                    var headers = {'content-type': opts.dataType};
                    return headers[header];
                };

                if (opts.dataType == 'json' || opts.dataType == 'script') {
                    var ta = doc.getElementsByTagName('textarea')[0];
                    xhr.responseText = ta ? ta.value : xhr.responseText;
                }
                else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
                    xhr.responseXML = toXml(xhr.responseText);
                }
                data = $.httpData(xhr, opts.dataType);
            }
            catch(e){
                ok = false;
                $.handleError(opts, xhr, 'error', e);
            }

            // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
            if (ok) {
                opts.success(data, 'success');
                if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
            }
            if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
            if (g && ! --$.active) $.event.trigger("ajaxStop");
            if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');

            // clean up
            setTimeout(function() {
                $io.remove();
                xhr.responseXML = null;
            }, 100);
        };

        function toXml(s, doc) {
            if (window.ActiveXObject) {
                doc = new ActiveXObject('Microsoft.XMLDOM');
                doc.async = 'false';
                doc.loadXML(s);
            }
            else
                doc = (new DOMParser()).parseFromString(s, 'text/xml');
            return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
        };
    };
};

/**
 * ajaxForm() provides a mechanism for fully automating form submission.
 *
 * The advantages of using this method instead of ajaxSubmit() are:
 *
 * 1: This method will include coordinates for <input type="image" /> elements (if the element
 *    is used to submit the form).
 * 2. This method will include the submit element's name/value data (for the element that was
 *    used to submit the form).
 * 3. This method binds the submit() method to the form for you.
 *
 * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
 * passes the options argument along after properly binding events for submit elements and
 * the form itself.
 */ 
$.fn.ajaxForm = function(options) {
    return this.ajaxFormUnbind().bind('submit.form-plugin',function() {
        $(this).ajaxSubmit(options);
        return false;
    }).each(function() {
        // store options in hash
        $(":submit,input:image", this).bind('click.form-plugin',function(e) {
            var form = this.form;
            form.clk = this;
            if (this.type == 'image') {
                if (e.offsetX != undefined) {
                    form.clk_x = e.offsetX;
                    form.clk_y = e.offsetY;
                } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
                    var offset = $(this).offset();
                    form.clk_x = e.pageX - offset.left;
                    form.clk_y = e.pageY - offset.top;
                } else {
                    form.clk_x = e.pageX - this.offsetLeft;
                    form.clk_y = e.pageY - this.offsetTop;
                }
            }
            // clear form vars
            setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 10);
        });
    });
};

// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
$.fn.ajaxFormUnbind = function() {
    this.unbind('submit.form-plugin');
    return this.each(function() {
        $(":submit,input:image", this).unbind('click.form-plugin');
    });

};

/**
 * formToArray() gathers form element data into an array of objects that can
 * be passed to any of the following ajax functions: $.get, $.post, or load.
 * Each object in the array has both a 'name' and 'value' property.  An example of
 * an array for a simple login form might be:
 *
 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
 *
 * It is this array that is passed to pre-submit callback functions provided to the
 * ajaxSubmit() and ajaxForm() methods.
 */
$.fn.formToArray = function(semantic) {
    var a = [];
    if (this.length == 0) return a;

    var form = this[0];
    var els = semantic ? form.getElementsByTagName('*') : form.elements;
    if (!els) return a;
    for(var i=0, max=els.length; i < max; i++) {
        var el = els[i];
        var n = el.name;
        if (!n) continue;

        if (semantic && form.clk && el.type == "image") {
            // handle image inputs on the fly when semantic == true
            if(!el.disabled && form.clk == el)
                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
            continue;
        }

        var v = $.fieldValue(el, true);
        if (v && v.constructor == Array) {
            for(var j=0, jmax=v.length; j < jmax; j++)
                a.push({name: n, value: v[j]});
        }
        else if (v !== null && typeof v != 'undefined')
            a.push({name: n, value: v});
    }

    if (!semantic && form.clk) {
        // input type=='image' are not found in elements array! handle them here
        var inputs = form.getElementsByTagName("input");
        for(var i=0, max=inputs.length; i < max; i++) {
            var input = inputs[i];
            var n = input.name;
            if(n && !input.disabled && input.type == "image" && form.clk == input)
                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
        }
    }
    return a;
};

/**
 * Serializes form data into a 'submittable' string. This method will return a string
 * in the format: name1=value1&amp;name2=value2
 */
$.fn.formSerialize = function(semantic) {
    //hand off to jQuery.param for proper encoding
    return $.param(this.formToArray(semantic));
};

/**
 * Serializes all field elements in the jQuery object into a query string.
 * This method will return a string in the format: name1=value1&amp;name2=value2
 */
$.fn.fieldSerialize = function(successful) {
    var a = [];
    this.each(function() {
        var n = this.name;
        if (!n) return;
        var v = $.fieldValue(this, successful);
        if (v && v.constructor == Array) {
            for (var i=0,max=v.length; i < max; i++)
                a.push({name: n, value: v[i]});
        }
        else if (v !== null && typeof v != 'undefined')
            a.push({name: this.name, value: v});
    });
    //hand off to jQuery.param for proper encoding
    return $.param(a);
};

/**
 * Returns the value(s) of the element in the matched set.  For example, consider the following form:
 *
 *  <form><fieldset>
 *      <input name="A" type="text" />
 *      <input name="A" type="text" />
 *      <input name="B" type="checkbox" value="B1" />
 *      <input name="B" type="checkbox" value="B2"/>
 *      <input name="C" type="radio" value="C1" />
 *      <input name="C" type="radio" value="C2" />
 *  </fieldset></form>
 *
 *  var v = $(':text').fieldValue();
 *  // if no values are entered into the text inputs
 *  v == ['','']
 *  // if values entered into the text inputs are 'foo' and 'bar'
 *  v == ['foo','bar']
 *
 *  var v = $(':checkbox').fieldValue();
 *  // if neither checkbox is checked
 *  v === undefined
 *  // if both checkboxes are checked
 *  v == ['B1', 'B2']
 *
 *  var v = $(':radio').fieldValue();
 *  // if neither radio is checked
 *  v === undefined
 *  // if first radio is checked
 *  v == ['C1']
 *
 * The successful argument controls whether or not the field element must be 'successful'
 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
 * The default value of the successful argument is true.  If this value is false the value(s)
 * for each element is returned.
 *
 * Note: This method *always* returns an array.  If no valid value can be determined the
 *       array will be empty, otherwise it will contain one or more values.
 */
$.fn.fieldValue = function(successful) {
    for (var val=[], i=0, max=this.length; i < max; i++) {
        var el = this[i];
        var v = $.fieldValue(el, successful);
        if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
            continue;
        v.constructor == Array ? $.merge(val, v) : val.push(v);
    }
    return val;
};

/**
 * Returns the value of the field element.
 */
$.fieldValue = function(el, successful) {
    var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
    if (typeof successful == 'undefined') successful = true;

    if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
        (t == 'checkbox' || t == 'radio') && !el.checked ||
        (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
        tag == 'select' && el.selectedIndex == -1))
            return null;

    if (tag == 'select') {
        var index = el.selectedIndex;
        if (index < 0) return null;
        var a = [], ops = el.options;
        var one = (t == 'select-one');
        var max = (one ? index+1 : ops.length);
        for(var i=(one ? index : 0); i < max; i++) {
            var op = ops[i];
            if (op.selected) {
                // extra pain for IE...
                var v = $.browser.msie && !(op.attributes['value'].specified) ? op.text : op.value;
                if (one) return v;
                a.push(v);
            }
        }
        return a;
    }
    return el.value;
};

/**
 * Clears the form data.  Takes the following actions on the form's input fields:
 *  - input text fields will have their 'value' property set to the empty string
 *  - select elements will have their 'selectedIndex' property set to -1
 *  - checkbox and radio inputs will have their 'checked' property set to false
 *  - inputs of type submit, button, reset, and hidden will *not* be effected
 *  - button elements will *not* be effected
 */
$.fn.clearForm = function() {
    return this.each(function() {
        $('input,select,textarea', this).clearFields();
    });
};

/**
 * Clears the selected form elements.
 */
$.fn.clearFields = $.fn.clearInputs = function() {
    return this.each(function() {
        var t = this.type, tag = this.tagName.toLowerCase();
        if (t == 'text' || t == 'password' || tag == 'textarea')
            this.value = '';
        else if (t == 'checkbox' || t == 'radio')
            this.checked = false;
        else if (tag == 'select')
            this.selectedIndex = -1;
    });
};

/**
 * Resets the form data.  Causes all form elements to be reset to their original value.
 */
$.fn.resetForm = function() {
    return this.each(function() {
        // guard against an input with the name of 'reset'
        // note that IE reports the reset function as an 'object'
        if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
            this.reset();
    });
};

/**
 * Enables or disables any matching elements.
 */
$.fn.enable = function(b) { 
    if (b == undefined) b = true;
    return this.each(function() { 
        this.disabled = !b 
    });
};

/**
 * Checks/unchecks any matching checkboxes or radio buttons and
 * selects/deselects and matching option elements.
 */
$.fn.selected = function(select) {
    if (select == undefined) select = true;
    return this.each(function() { 
        var t = this.type;
        if (t == 'checkbox' || t == 'radio')
            this.checked = select;
        else if (this.tagName.toLowerCase() == 'option') {
            var $sel = $(this).parent('select');
            if (select && $sel[0] && $sel[0].type == 'select-one') {
                // deselect all other options
                $sel.find('option').selected(false);
            }
            this.selected = select;
        }
    });
};

// helper fn for console logging
// set $.fn.ajaxSubmit.debug to true to enable debug logging
function log() {
    if ($.fn.ajaxSubmit.debug && window.console && window.console.log)
        window.console.log('[jquery.form] ' + Array.prototype.join.call(arguments,''));
};

})(jQuery);
/*
 * jQuery Tooltip plugin 1.3
 *
 * http://bassistance.de/jquery-plugins/jquery-plugin-tooltip/
 * http://docs.jquery.com/Plugins/Tooltip
 *
 * Copyright (c) 2006 - 2008 JÃ¶rn Zaefferer
 *
 * $Id: jquery.tooltip.js 5741 2008-06-21 15:22:16Z joern.zaefferer $
 * 
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 */
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}(';(8($){j e={},9,m,B,A=$.2u.2g&&/29\\s(5\\.5|6\\.)/.1M(1H.2t),M=12;$.k={w:12,1h:{Z:25,r:12,1d:19,X:"",G:15,E:15,16:"k"},2s:8(){$.k.w=!$.k.w}};$.N.1v({k:8(a){a=$.1v({},$.k.1h,a);1q(a);g 2.F(8(){$.1j(2,"k",a);2.11=e.3.n("1g");2.13=2.m;$(2).24("m");2.22=""}).21(1e).1U(q).1S(q)},H:A?8(){g 2.F(8(){j b=$(2).n(\'Y\');4(b.1J(/^o\\(["\']?(.*\\.1I)["\']?\\)$/i)){b=1F.$1;$(2).n({\'Y\':\'1D\',\'1B\':"2r:2q.2m.2l(2j=19, 2i=2h, 1p=\'"+b+"\')"}).F(8(){j a=$(2).n(\'1o\');4(a!=\'2f\'&&a!=\'1u\')$(2).n(\'1o\',\'1u\')})}})}:8(){g 2},1l:A?8(){g 2.F(8(){$(2).n({\'1B\':\'\',Y:\'\'})})}:8(){g 2},1x:8(){g 2.F(8(){$(2)[$(2).D()?"l":"q"]()})},o:8(){g 2.1k(\'28\')||2.1k(\'1p\')}});8 1q(a){4(e.3)g;e.3=$(\'<t 16="\'+a.16+\'"><10></10><t 1i="f"></t><t 1i="o"></t></t>\').27(K.f).q();4($.N.L)e.3.L();e.m=$(\'10\',e.3);e.f=$(\'t.f\',e.3);e.o=$(\'t.o\',e.3)}8 7(a){g $.1j(a,"k")}8 1f(a){4(7(2).Z)B=26(l,7(2).Z);p l();M=!!7(2).M;$(K.f).23(\'W\',u);u(a)}8 1e(){4($.k.w||2==9||(!2.13&&!7(2).U))g;9=2;m=2.13;4(7(2).U){e.m.q();j a=7(2).U.1Z(2);4(a.1Y||a.1V){e.f.1c().T(a)}p{e.f.D(a)}e.f.l()}p 4(7(2).18){j b=m.1T(7(2).18);e.m.D(b.1R()).l();e.f.1c();1Q(j i=0,R;(R=b[i]);i++){4(i>0)e.f.T("<1P/>");e.f.T(R)}e.f.1x()}p{e.m.D(m).l();e.f.q()}4(7(2).1d&&$(2).o())e.o.D($(2).o().1O(\'1N://\',\'\')).l();p e.o.q();e.3.P(7(2).X);4(7(2).H)e.3.H();1f.1L(2,1K)}8 l(){B=S;4((!A||!$.N.L)&&7(9).r){4(e.3.I(":17"))e.3.Q().l().O(7(9).r,9.11);p e.3.I(\':1a\')?e.3.O(7(9).r,9.11):e.3.1G(7(9).r)}p{e.3.l()}u()}8 u(c){4($.k.w)g;4(c&&c.1W.1X=="1E"){g}4(!M&&e.3.I(":1a")){$(K.f).1b(\'W\',u)}4(9==S){$(K.f).1b(\'W\',u);g}e.3.V("z-14").V("z-1A");j b=e.3[0].1z;j a=e.3[0].1y;4(c){b=c.2o+7(9).E;a=c.2n+7(9).G;j d=\'1w\';4(7(9).2k){d=$(C).1r()-b;b=\'1w\'}e.3.n({E:b,14:d,G:a})}j v=z(),h=e.3[0];4(v.x+v.1s<h.1z+h.1n){b-=h.1n+20+7(9).E;e.3.n({E:b+\'1C\'}).P("z-14")}4(v.y+v.1t<h.1y+h.1m){a-=h.1m+20+7(9).G;e.3.n({G:a+\'1C\'}).P("z-1A")}}8 z(){g{x:$(C).2e(),y:$(C).2d(),1s:$(C).1r(),1t:$(C).2p()}}8 q(a){4($.k.w)g;4(B)2c(B);9=S;j b=7(2);8 J(){e.3.V(b.X).q().n("1g","")}4((!A||!$.N.L)&&b.r){4(e.3.I(\':17\'))e.3.Q().O(b.r,0,J);p e.3.Q().2b(b.r,J)}p J();4(7(2).H)e.3.1l()}})(2a);',62,155,'||this|parent|if|||settings|function|current||||||body|return|||var|tooltip|show|title|css|url|else|hide|fade||div|update||blocked|||viewport|IE|tID|window|html|left|each|top|fixPNG|is|complete|document|bgiframe|track|fn|fadeTo|addClass|stop|part|null|append|bodyHandler|removeClass|mousemove|extraClass|backgroundImage|delay|h3|tOpacity|false|tooltipText|right||id|animated|showBody|true|visible|unbind|empty|showURL|save|handle|opacity|defaults|class|data|attr|unfixPNG|offsetHeight|offsetWidth|position|src|createHelper|width|cx|cy|relative|extend|auto|hideWhenEmpty|offsetTop|offsetLeft|bottom|filter|px|none|OPTION|RegExp|fadeIn|navigator|png|match|arguments|apply|test|http|replace|br|for|shift|click|split|mouseout|jquery|target|tagName|nodeType|call||mouseover|alt|bind|removeAttr|200|setTimeout|appendTo|href|MSIE|jQuery|fadeOut|clearTimeout|scrollTop|scrollLeft|absolute|msie|crop|sizingMethod|enabled|positionLeft|AlphaImageLoader|Microsoft|pageY|pageX|height|DXImageTransform|progid|block|userAgent|browser'.split('|'),0,{}))/*
 * Autocomplete - jQuery plugin 1.0.2
 *
 * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, JÃ¶rn Zaefferer
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Revision: $Id: jquery.autocomplete.js 5747 2008-06-25 18:30:55Z joern.zaefferer $
 *
 */

;(function($) {
	
$.fn.extend({
	autocomplete: function(urlOrData, options) {
		var isUrl = typeof urlOrData == "string";
		options = $.extend({}, $.Autocompleter.defaults, {
			url: isUrl ? urlOrData : null,
			data: isUrl ? null : urlOrData,
			delay: isUrl ? $.Autocompleter.defaults.delay : 10,
			max: options && !options.scroll ? 10 : 150
		}, options);
		
		// if highlight is set to false, replace it with a do-nothing function
		options.highlight = options.highlight || function(value) { return value; };
		
		// if the formatMatch option is not specified, then use formatItem for backwards compatibility
		options.formatMatch = options.formatMatch || options.formatItem;
		
		return this.each(function() {
			new $.Autocompleter(this, options);
		});
	},
	result: function(handler) {
		return this.bind("result", handler);
	},
	search: function(handler) {
		return this.trigger("search", [handler]);
	},
	flushCache: function() {
		return this.trigger("flushCache");
	},
	setOptions: function(options){
		return this.trigger("setOptions", [options]);
	},
	unautocomplete: function() {
		return this.trigger("unautocomplete");
	}
});

$.Autocompleter = function(input, options) {

	var KEY = {
		UP: 38,
		DOWN: 40,
		DEL: 46,
		TAB: 9,
		RETURN: 13,
		ESC: 27,
		COMMA: 188,
		PAGEUP: 33,
		PAGEDOWN: 34,
		BACKSPACE: 8
	};

	// Create $ object for input element
	var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);

	var timeout;
	var previousValue = "";
	var cache = $.Autocompleter.Cache(options);
	var hasFocus = 0;
	var lastKeyPressCode;
	var config = {
		mouseDownOnSelect: false
	};
	var select = $.Autocompleter.Select(options, input, selectCurrent, config);
	
	var blockSubmit;
	
	// prevent form submit in opera when selecting with return key
	$.browser.opera && $(input.form).bind("submit.autocomplete", function() {
		if (blockSubmit) {
			blockSubmit = false;
			return false;
		}
	});
	
	// only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
	$input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
		// track last key pressed
		lastKeyPressCode = event.keyCode;
		switch(event.keyCode) {
		
			case KEY.UP:
				event.preventDefault();
				if ( select.visible() ) {
					select.prev();
				} else {
					onChange(0, true);
				}
				break;
				
			case KEY.DOWN:
				event.preventDefault();
				if ( select.visible() ) {
					select.next();
				} else {
					onChange(0, true);
				}
				break;
				
			case KEY.PAGEUP:
				event.preventDefault();
				if ( select.visible() ) {
					select.pageUp();
				} else {
					onChange(0, true);
				}
				break;
				
			case KEY.PAGEDOWN:
				event.preventDefault();
				if ( select.visible() ) {
					select.pageDown();
				} else {
					onChange(0, true);
				}
				break;
			
			// matches also semicolon
			case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
			case KEY.TAB:
			case KEY.RETURN:
				if( selectCurrent() ) {
					// stop default to prevent a form submit, Opera needs special handling
					event.preventDefault();
					blockSubmit = true;
					return false;
				}
				break;
				
			case KEY.ESC:
				select.hide();
				break;
				
			default:
				clearTimeout(timeout);
				timeout = setTimeout(onChange, options.delay);
				break;
		}
	}).focus(function(){
		// track whether the field has focus, we shouldn't process any
		// results if the field no longer has focus
		hasFocus++;
	}).blur(function() {
		hasFocus = 0;
		if (!config.mouseDownOnSelect) {
			hideResults();
		}
	}).click(function() {
		// show select when clicking in a focused field
		if ( hasFocus++ > 1 && !select.visible() ) {
			onChange(0, true);
		}
	}).bind("search", function() {
		// TODO why not just specifying both arguments?
		var fn = (arguments.length > 1) ? arguments[1] : null;
		function findValueCallback(q, data) {
			var result;
			if( data && data.length ) {
				for (var i=0; i < data.length; i++) {
					if( data[i].result.toLowerCase() == q.toLowerCase() ) {
						result = data[i];
						break;
					}
				}
			}
			if( typeof fn == "function" ) fn(result);
			else $input.trigger("result", result && [result.data, result.value]);
		}
		$.each(trimWords($input.val()), function(i, value) {
			request(value, findValueCallback, findValueCallback);
		});
	}).bind("flushCache", function() {
		cache.flush();
	}).bind("setOptions", function() {
		$.extend(options, arguments[1]);
		// if we've updated the data, repopulate
		if ( "data" in arguments[1] )
			cache.populate();
	}).bind("unautocomplete", function() {
		select.unbind();
		$input.unbind();
		$(input.form).unbind(".autocomplete");
	});
	
	
	function selectCurrent() {
		var selected = select.selected();
		if( !selected )
			return false;
		
		var v = selected.result;
		previousValue = v;
		
		if ( options.multiple ) {
			var words = trimWords($input.val());
			if ( words.length > 1 ) {
				v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v;
			}
			v += options.multipleSeparator;
		}
		
		$input.val(v);
		hideResultsNow();
		$input.trigger("result", [selected.data, selected.value]);
		return true;
	}
	
	function onChange(crap, skipPrevCheck) {
		if( lastKeyPressCode == KEY.DEL ) {
			select.hide();
			return;
		}
		
		var currentValue = $input.val();
		
		if ( !skipPrevCheck && currentValue == previousValue )
			return;
		
		previousValue = currentValue;
		
		currentValue = lastWord(currentValue);
		if ( currentValue.length >= options.minChars) {
			$input.addClass(options.loadingClass);
			if (!options.matchCase)
				currentValue = currentValue.toLowerCase();
			request(currentValue, receiveData, hideResultsNow);
		} else {
			stopLoading();
			select.hide();
		}
	};
	
	function trimWords(value) {
		if ( !value ) {
			return [""];
		}
		var words = value.split( options.multipleSeparator );
		var result = [];
		$.each(words, function(i, value) {
			if ( $.trim(value) )
				result[i] = $.trim(value);
		});
		return result;
	}
	
	function lastWord(value) {
		if ( !options.multiple )
			return value;
		var words = trimWords(value);
		return words[words.length - 1];
	}
	
	// fills in the input box w/the first match (assumed to be the best match)
	// q: the term entered
	// sValue: the first matching result
	function autoFill(q, sValue){
		// autofill in the complete box w/the first match as long as the user hasn't entered in more data
		// if the last user key pressed was backspace, don't autofill
		if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
			// fill in the value (keep the case the user has typed)
			$input.val($input.val() + sValue.substring(lastWord(previousValue).length));
			// select the portion of the value not typed by the user (so the next character will erase)
			$.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length);
		}
	};

	function hideResults() {
		clearTimeout(timeout);
		timeout = setTimeout(hideResultsNow, 200);
	};

	function hideResultsNow() {
		var wasVisible = select.visible();
		select.hide();
		clearTimeout(timeout);
		stopLoading();
		if (options.mustMatch) {
			// call search and run callback
			$input.search(
				function (result){
					// if no value found, clear the input box
					if( !result ) {
						if (options.multiple) {
							var words = trimWords($input.val()).slice(0, -1);
							$input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
						}
						else
							$input.val( "" );
					}
				}
			);
		}
		if (wasVisible)
			// position cursor at end of input field
			$.Autocompleter.Selection(input, input.value.length, input.value.length);
	};

	function receiveData(q, data) {
		if ( data && data.length && hasFocus ) {
			stopLoading();
			select.display(data, q);
			autoFill(q, data[0].value);
			select.show();
		} else {
			hideResultsNow();
		}
	};

	function request(term, success, failure) {
		if (!options.matchCase)
			term = term.toLowerCase();
		var data = cache.load(term);
		// recieve the cached data
		if (data && data.length) {
			success(term, data);
		// if an AJAX url has been supplied, try loading the data now
		} else if( (typeof options.url == "string") && (options.url.length > 0) ){
			
			var extraParams = {
				timestamp: +new Date()
			};
			$.each(options.extraParams, function(key, param) {
				extraParams[key] = typeof param == "function" ? param() : param;
			});
			
			$.ajax({
				// try to leverage ajaxQueue plugin to abort previous requests
				mode: "abort",
				// limit abortion to this input
				port: "autocomplete" + input.name,
				dataType: options.dataType,
				url: options.url,
				data: $.extend({
					q: encodeURIComponent(lastWord(term)),
					limit: options.max
				}, extraParams),
				success: function(data) {
					var parsed = options.parse && options.parse(data) || parse(data);
					cache.add(term, parsed);
					success(term, parsed);
				}
			});
		} else {
			// if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
			select.emptyList();
			failure(term);
		}
	};
	
	function parse(data) {
		var parsed = [];
		var rows = data.split("\n");
		for (var i=0; i < rows.length; i++) {
			var row = $.trim(rows[i]);
			if (row) {
				row = row.split("|");
				parsed[parsed.length] = {
					data: row,
					value: row[0],
					result: options.formatResult && options.formatResult(row, row[0]) || row[0]
				};
			}
		}
		return parsed;
	};

	function stopLoading() {
		$input.removeClass(options.loadingClass);
	};

};

$.Autocompleter.defaults = {
	inputClass: "ac_input",
	resultsClass: "ac_results",
	loadingClass: "ac_loading",
	minChars: 1,
	delay: 400,
	matchCase: false,
	matchSubset: true,
	matchContains: false,
	cacheLength: 10,
	max: 100,
	mustMatch: false,
	extraParams: {},
	selectFirst: true,
	formatItem: function(row) { return row[0]; },
	formatMatch: null,
	autoFill: false,
	width: 0,
	multiple: false,
	multipleSeparator: ", ",
	highlight: function(value, term) {
		return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
	},
    scroll: true,
    scrollHeight: 180
};

$.Autocompleter.Cache = function(options) {

	var data = {};
	var length = 0;
	
	function matchSubset(s, sub) {
		if (!options.matchCase) 
			s = s.toLowerCase();
		var i = s.indexOf(sub);
		if (i == -1) return false;
		return i == 0 || options.matchContains;
	};
	
	function add(q, value) {
		if (length > options.cacheLength){
			flush();
		}
		if (!data[q]){ 
			length++;
		}
		data[q] = value;
	}
	
	function populate(){
		if( !options.data ) return false;
		// track the matches
		var stMatchSets = {},
			nullData = 0;

		// no url was specified, we need to adjust the cache length to make sure it fits the local data store
		if( !options.url ) options.cacheLength = 1;
		
		// track all options for minChars = 0
		stMatchSets[""] = [];
		
		// loop through the array and create a lookup structure
		for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
			var rawValue = options.data[i];
			// if rawValue is a string, make an array otherwise just reference the array
			rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
			
			var value = options.formatMatch(rawValue, i+1, options.data.length);
			if ( value === false )
				continue;
				
			var firstChar = value.charAt(0).toLowerCase();
			// if no lookup array for this character exists, look it up now
			if( !stMatchSets[firstChar] ) 
				stMatchSets[firstChar] = [];

			// if the match is a string
			var row = {
				value: value,
				data: rawValue,
				result: options.formatResult && options.formatResult(rawValue) || value
			};
			
			// push the current match into the set list
			stMatchSets[firstChar].push(row);

			// keep track of minChars zero items
			if ( nullData++ < options.max ) {
				stMatchSets[""].push(row);
			}
		};

		// add the data items to the cache
		$.each(stMatchSets, function(i, value) {
			// increase the cache size
			options.cacheLength++;
			// add to the cache
			add(i, value);
		});
	}
	
	// populate any existing data
	setTimeout(populate, 25);
	
	function flush(){
		data = {};
		length = 0;
	}
	
	return {
		flush: flush,
		add: add,
		populate: populate,
		load: function(q) {
			if (!options.cacheLength || !length)
				return null;
			/* 
			 * if dealing w/local data and matchContains than we must make sure
			 * to loop through all the data collections looking for matches
			 */
			if( !options.url && options.matchContains ){
				// track all matches
				var csub = [];
				// loop through all the data grids for matches
				for( var k in data ){
					// don't search through the stMatchSets[""] (minChars: 0) cache
					// this prevents duplicates
					if( k.length > 0 ){
						var c = data[k];
						$.each(c, function(i, x) {
							// if we've got a match, add it to the array
							if (matchSubset(x.value, q)) {
								csub.push(x);
							}
						});
					}
				}				
				return csub;
			} else 
			// if the exact item exists, use it
			if (data[q]){
				return data[q];
			} else
			if (options.matchSubset) {
				for (var i = q.length - 1; i >= options.minChars; i--) {
					var c = data[q.substr(0, i)];
					if (c) {
						var csub = [];
						$.each(c, function(i, x) {
							if (matchSubset(x.value, q)) {
								csub[csub.length] = x;
							}
						});
						return csub;
					}
				}
			}
			return null;
		}
	};
};

$.Autocompleter.Select = function (options, input, select, config) {
	var CLASSES = {
		ACTIVE: "ac_over"
	};
	
	var listItems,
		active = -1,
		data,
		term = "",
		needsInit = true,
		element,
		list;
	
	// Create results
	function init() {
		if (!needsInit)
			return;
		element = $("<div/>")
		.hide()
		.addClass(options.resultsClass)
		.css("position", "absolute")
		.appendTo(document.body);
	
		list = $("<ul/>").appendTo(element).mouseover( function(event) {
			if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
	            active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
			    $(target(event)).addClass(CLASSES.ACTIVE);            
	        }
		}).click(function(event) {
			$(target(event)).addClass(CLASSES.ACTIVE);
			select();
			// TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
			input.focus();
			return false;
		}).mousedown(function() {
			config.mouseDownOnSelect = true;
		}).mouseup(function() {
			config.mouseDownOnSelect = false;
		});
		
		if( options.width > 0 )
			element.css("width", options.width);
			
		needsInit = false;
	} 
	
	function target(event) {
		var element = event.target;
		while(element && element.tagName != "LI")
			element = element.parentNode;
		// more fun with IE, sometimes event.target is empty, just ignore it then
		if(!element)
			return [];
		return element;
	}

	function moveSelect(step) {
		listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
		movePosition(step);
        var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
        if(options.scroll) {
            var offset = 0;
            listItems.slice(0, active).each(function() {
				offset += this.offsetHeight;
			});
            if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
                list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
            } else if(offset < list.scrollTop()) {
                list.scrollTop(offset);
            }
        }
	};
	
	function movePosition(step) {
		active += step;
		if (active < 0) {
			active = listItems.size() - 1;
		} else if (active >= listItems.size()) {
			active = 0;
		}
	}
	
	function limitNumberOfItems(available) {
		return options.max && options.max < available
			? options.max
			: available;
	}
	
	function fillList() {
		list.empty();
		var max = limitNumberOfItems(data.length);
		for (var i=0; i < max; i++) {
			if (!data[i])
				continue;
			var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
			if ( formatted === false )
				continue;
			var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
			$.data(li, "ac_data", data[i]);
		}
		listItems = list.find("li");
		if ( options.selectFirst ) {
			listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
			active = 0;
		}
		// apply bgiframe if available
		if ( $.fn.bgiframe )
			list.bgiframe();
	}
	
	return {
		display: function(d, q) {
			init();
			data = d;
			term = q;
			fillList();
		},
		next: function() {
			moveSelect(1);
		},
		prev: function() {
			moveSelect(-1);
		},
		pageUp: function() {
			if (active != 0 && active - 8 < 0) {
				moveSelect( -active );
			} else {
				moveSelect(-8);
			}
		},
		pageDown: function() {
			if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
				moveSelect( listItems.size() - 1 - active );
			} else {
				moveSelect(8);
			}
		},
		hide: function() {
			element && element.hide();
			listItems && listItems.removeClass(CLASSES.ACTIVE);
			active = -1;
		},
		visible : function() {
			return element && element.is(":visible");
		},
		current: function() {
			return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
		},
		show: function() {
			var offset = $(input).offset();
			element.css({
				width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
				top: offset.top + input.offsetHeight,
				left: offset.left
			}).show();
            if(options.scroll) {
                list.scrollTop(0);
                list.css({
					maxHeight: options.scrollHeight,
					overflow: 'auto'
				});
				
                if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
					var listHeight = 0;
					listItems.each(function() {
						listHeight += this.offsetHeight;
					});
					var scrollbarsVisible = listHeight > options.scrollHeight;
                    list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
					if (!scrollbarsVisible) {
						// IE doesn't recalculate width when scrollbar disappears
						listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
					}
                }
                
            }
		},
		selected: function() {
			var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
			return selected && selected.length && $.data(selected[0], "ac_data");
		},
		emptyList: function (){
			list && list.empty();
		},
		unbind: function() {
			element && element.remove();
		}
	};
};

$.Autocompleter.Selection = function(field, start, end) {
	if( field.createTextRange ){
		var selRange = field.createTextRange();
		selRange.collapse(true);
		selRange.moveStart("character", start);
		selRange.moveEnd("character", end);
		selRange.select();
	} else if( field.setSelectionRange ){
		field.setSelectionRange(start, end);
	} else {
		if( field.selectionStart ){
			field.selectionStart = start;
			field.selectionEnd = end;
		}
	}
	field.focus();
};

})(jQuery);/*
 * Thickbox 3.1 - One Box To Rule Them All.
 * By Cody Lindley (http://www.codylindley.com)
 * Copyright (c) 2007 cody lindley
 * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php
*/

var tb_pathToImage = "../../img/loadingAnimation.gif";

/*!!!!!!!!!!!!!!!!! edit below this line at your own risk !!!!!!!!!!!!!!!!!!!!!!!*/

//on page load call tb_init
$(function(){   
 	tb_init('a.thickbox, area.thickbox, input.thickbox'); //pass where to apply thickbox
 	imgLoader = new Image();
	imgLoader.src = tb_pathToImage;
});

//add thickbox to href & area elements that have a class of .thickbox
function tb_init(domChunk)
{
	$(domChunk).click(function()
	{
		var t = this.title || this.name || null;
		var a = this.href || this.alt;
		var g = this.rel || false;
		tb_show(t,a,g);
		this.blur();
		return false;
	});
}

function tb_reset() {
	tb_init('a.thickbox, area.thickbox, input.thickbox');//pass where to apply thickbox
	imgLoader = new Image();// preload image
	imgLoader.src = tb_pathToImage;
}

function tb_show(caption, url, imageGroup) {//function called when the user clicks on a thickbox link

	try {
		if (typeof document.body.style.maxHeight === "undefined") {//if IE 6
			$("body","html").css({height: "100%", width: "100%"});
			$("html").css("overflow","hidden");
			if (document.getElementById("TB_HideSelect") === null) {//iframe to hide select elements in ie6
				$("body").append("<iframe id='TB_HideSelect' scrolling='no' frameborder='0'></iframe><div id='TB_overlay'></div><div id='TB_window'><div id='TB_top'><div id='TB_bottom'><div id='TB_content'></div></div></div></div>");
				$("#TB_overlay").click(tb_remove);
			}
		}else{//all others
			if(document.getElementById("TB_overlay") === null){
				$("body").append("<div id='TB_overlay'></div><div id='TB_window'><div id='TB_top'><div id='TB_bottom'><div id='TB_content'></div></div></div></div>");
				$("#TB_overlay").click(tb_remove);
				if (typeof $.ifixpng !== 'undefined')
				{
					$.ifixpng('img/pixel.gif');
					$('#TB_title').ifixpng();
				}
			}
		}
		
		if(tb_detectMacXFF()){
			$("#TB_overlay").addClass("TB_overlayMacFFBGHack");//use png overlay so hide flash
		}else{
			$("#TB_overlay").addClass("TB_overlayBG");//use background and opacity
		}
		
		if(caption===null){caption="";}
		$("body").append("<div id='TB_load'><img src='"+imgLoader.src+"' /></div>");//add loader to the page
		$('#TB_load').show();//show loader
		
		var baseURL;
	   if(url.indexOf("?")!==-1){ //ff there is a query string involved
			baseURL = url.substr(0, url.indexOf("?"));
	   }else{ 
	   		baseURL = url;
	   }
	   
	   var urlString = /\.jpg$|\.jpeg$|\.png$|\.gif$|\.bmp$/;
	   var urlType = baseURL.toLowerCase().match(urlString);

		if(urlType == '.jpg' || urlType == '.jpeg' || urlType == '.png' || urlType == '.gif' || urlType == '.bmp'){//code to show images
				
			TB_PrevCaption = "";
			TB_PrevURL = "";
			TB_PrevHTML = "";
			TB_NextCaption = "";
			TB_NextURL = "";
			TB_NextHTML = "";
			TB_imageCount = "";
			TB_FoundURL = false;
			if(imageGroup){
				TB_TempArray = $("a[@rel="+imageGroup+"]").get();
				for (TB_Counter = 0; ((TB_Counter < TB_TempArray.length) && (TB_NextHTML === "")); TB_Counter++) {
					var urlTypeTemp = TB_TempArray[TB_Counter].href.toLowerCase().match(urlString);
						if (!(TB_TempArray[TB_Counter].href == url)) {						
							if (TB_FoundURL) {
								TB_NextCaption = TB_TempArray[TB_Counter].title;
								TB_NextURL = TB_TempArray[TB_Counter].href;
								TB_NextHTML = "<span id='TB_next'>&nbsp;&nbsp;<a href='#'>Next &gt;</a></span>";
							} else {
								TB_PrevCaption = TB_TempArray[TB_Counter].title;
								TB_PrevURL = TB_TempArray[TB_Counter].href;
								TB_PrevHTML = "<span id='TB_prev'>&nbsp;&nbsp;<a href='#'>&lt; Prev</a></span>";
							}
						} else {
							TB_FoundURL = true;
							TB_imageCount = "Image " + (TB_Counter + 1) +" of "+ (TB_TempArray.length);											
						}
				}
			}

			imgPreloader = new Image();
			imgPreloader.onload = function(){		
			imgPreloader.onload = null;
				
			// Resizing large images - orginal by Christian Montoya edited by me.
			var pagesize = tb_getPageSize();
			var x = pagesize[0] - 150;
			var y = pagesize[1] - 150;
			var imageWidth = imgPreloader.width;
			var imageHeight = imgPreloader.height;
			if (imageWidth > x) {
				imageHeight = imageHeight * (x / imageWidth); 
				imageWidth = x; 
				if (imageHeight > y) { 
					imageWidth = imageWidth * (y / imageHeight); 
					imageHeight = y; 
				}
			} else if (imageHeight > y) { 
				imageWidth = imageWidth * (y / imageHeight); 
				imageHeight = y; 
				if (imageWidth > x) { 
					imageHeight = imageHeight * (x / imageWidth); 
					imageWidth = x;
				}
			}
			// End Resizing
			
			TB_WIDTH = imageWidth + 30;
			TB_HEIGHT = imageHeight + 60;
			$("#TB_window").append("<a href='' id='TB_ImageOff' title='Close'><img id='TB_Image' src='"+url+"' width='"+imageWidth+"' height='"+imageHeight+"' alt='"+caption+"'/></a>" + "<div id='TB_caption'>"+caption+"<div id='TB_secondLine'>" + TB_imageCount + TB_PrevHTML + TB_NextHTML + "</div></div><div id='TB_closeWindow'><a href='#' id='TB_closeWindowButton' title='Close'>close</a> or Esc Key</div>"); 		
			
			$("#TB_closeWindowButton").click(tb_remove);
			
			if (!(TB_PrevHTML === "")) {
				function goPrev(){
					if($(document).unbind("click",goPrev)){$(document).unbind("click",goPrev);}
					$("#TB_window").remove();
					$("body").append("<div id='TB_window'></div>");
					tb_show(TB_PrevCaption, TB_PrevURL, imageGroup);
					return false;	
				}
				$("#TB_prev").click(goPrev);
			}
			
			if (!(TB_NextHTML === "")) {		
				function goNext(){
					$("#TB_window").remove();
					$("body").append("<div id='TB_window'></div>");
					tb_show(TB_NextCaption, TB_NextURL, imageGroup);				
					return false;	
				}
				$("#TB_next").click(goNext);
				
			}

			document.onkeydown = function(e){ 	
        if (e == null) { // ie
					keycode = event.keyCode;
				} else { // mozilla
					keycode = e.which;
				}
				if(keycode == 27){ // close
					tb_remove();
				} else if(keycode == 190){ // display previous image
					if(!(TB_NextHTML == "")){
						document.onkeydown = "";
						goNext();
					}
				} else if(keycode == 188){ // display next image
					if(!(TB_PrevHTML == "")){
						document.onkeydown = "";
						goPrev();
					}
				}	
			};
			
			tb_position();
			$("#TB_load").remove();
			$("#TB_ImageOff").click(tb_remove);
			$("#TB_window").css({display:"block"}); //for safari using css instead of show
			};
			
			imgPreloader.src = url;
		}else{//code to show html
			
			var queryString = url.replace(/^[^\?]+\??/,'');
			var params = tb_parseQuery( queryString );

			TB_WIDTH = (params['width']*1) || 500; //defaults to 630 if no paramaters were added to URL
			TB_HEIGHT = (params['height']*1) || 500; //defaults to 440 if no paramaters were added to URL
			ajaxContentW = TB_WIDTH;
			ajaxContentH = TB_HEIGHT;

			if(url.indexOf('TB_iframe') != -1){// either iframe or ajax window		
					urlNoQuery = url.split('TB_');
					$("#TB_iframeContent").remove();
					if(params['modal'] != "true"){//iframe no modal
						$("#TB_content").append("<div id='TB_title'><div id='TB_closeAjaxWindow'><a href='#' id='TB_closeWindowButton' title='Fermer'><img src='" + basedir + "/img/thickbox/closeBtRed.png' class='png' /></a></div></div><iframe frameborder='0' scrolling='no' src='"+url+"' id='TB_iframeContent' name='TB_iframeContent"+Math.round(Math.random()*1000)+"' onload='tb_showIframe()' style='width:"+(ajaxContentW - 16)+"px;height:"+(ajaxContentH - 16)+"px;' > </iframe>");
					}else{//iframe modal
					$("#TB_overlay").unbind();
						$("#TB_content").append("<iframe frameborder='0' src='"+url+"' id='TB_iframeContent' name='TB_iframeContent"+Math.round(Math.random()*1000)+"' onload='tb_showIframe()' style='width:"+(ajaxContentW - 16)+"px;height:"+(ajaxContentH - 16)+"px;'> </iframe>");
					}
			}else{// not an iframe, ajax
					if($("#TB_window").css("display") != "block"){
						if(params['modal'] != "true"){//ajax no modal
						$("#TB_window").append("<div id='TB_title' class='png' ><div id='TB_ajaxWindowTitle'>"+caption+"</div><div id='TB_closeAjaxWindow'><a href='#' id='TB_closeWindowButton'>close</a> or Esc Key</div></div><div id='TB_ajaxContent' style='width:"+ajaxContentW+"px;height:"+ajaxContentH+"px'></div>");
						}else{//ajax modal
						$("#TB_overlay").unbind();
						$("#TB_window").append("<div id='TB_ajaxContent' class='TB_modal' style='width:"+ajaxContentW+"px;height:"+ajaxContentH+"px;'></div>");	
						}
					}else{//this means the window is already up, we are just loading new content via ajax
						$("#TB_ajaxContent")[0].style.width = ajaxContentW +"px";
						$("#TB_ajaxContent")[0].style.height = ajaxContentH +"px";
						$("#TB_ajaxContent")[0].scrollTop = 0;
						$("#TB_ajaxWindowTitle").html(caption);
					}
			}
					
			$("#TB_closeWindowButton").click(tb_remove);
			
				if(url.indexOf('TB_inline') != -1){	
					$("#TB_ajaxContent").append($('#' + params['inlineId']).children());
					$("#TB_window").unload(function () {
						$('#' + params['inlineId']).append( $("#TB_ajaxContent").children() ); // move elements back when you're finished
					});
					tb_position();
					$("#TB_load").remove();
					$("#TB_window").css({display:"block"}); 
				}else if(url.indexOf('TB_iframe') != -1){
					tb_position();
					if($.browser.safari){//safari needs help because it will not fire iframe onload
						$("#TB_load").remove();
						$("#TB_window").css({display:"block"});
					}
				}else{
					$("#TB_ajaxContent").load(url += "&random=" + (new Date().getTime()),function(){//to do a post change this load method
						tb_position();
						$("#TB_load").remove();
						tb_init("#TB_ajaxContent a.thickbox");
						$("#TB_window").css({display:"block"});
					});
				}
			
		}

		if(!params['modal']){
			document.onkeyup = function(e){ 	
				if (e == null) { // ie
					keycode = event.keyCode;
				} else { // mozilla
					keycode = e.which;
				}
				if(keycode == 27){ // close
					tb_remove();
				}	
			};
		}
		
	} catch(e) {
		//nothing here
	}
}

//helper functions below
function tb_showIframe(){
	
	/** Nico: here we manually resize the iframe/TB_window depending on the iframe content
	 *  Patch starts here
	 */
	if (typeof isSameDomain === 'function')
		sameDomain = isSameDomain("#TB_iframeContent");
	else
		sameDomain = true;
	
	if (sameDomain === true)
	{		
		$("#TB_iframeContent").css({width: '434px', height:'442px'});
		$("#TB_window").css({width: '450px', height:'442px'});
	}
	else
	{
		$("#TB_iframeContent").css({width: '434px', height:'261px'});
		$("#TB_window").css({width: '450px', height:'261px'});		
	}
	/** /Patch */

	$("#TB_load").remove();
	$("#TB_window").css({display:"block"});
}

function tb_remove() {
 	$("#TB_imageOff").unbind("click");
	$("#TB_closeWindowButton").unbind("click");
	$("#TB_window").fadeOut("fast",function(){$('#TB_window,#TB_overlay,#TB_HideSelect').trigger("unload").unbind().remove();});
	$("#TB_load").remove();
	if (typeof document.body.style.maxHeight == "undefined") {//if IE 6
		$("body","html").css({height: "auto", width: "auto"});
		$("html").css("overflow","");
	}
	document.onkeydown = "";
	document.onkeyup = "";
	return false;
}

function tb_position()
{
	$("#TB_window").css({marginLeft: '-' + parseInt((TB_WIDTH / 2),10) + 'px', width: TB_WIDTH + 'px'});

	if ( !(jQuery.browser.msie && jQuery.browser.version < 7)) { // take away IE6
		$("#TB_window").css({marginTop: '-' + parseInt((TB_HEIGHT / 2),10) + 'px'});		
	}
}

function tb_parseQuery ( query ) {
   var Params = {};
   if ( ! query ) {return Params;}// return empty object
   var Pairs = query.split(/[;&]/);
   for ( var i = 0; i < Pairs.length; i++ ) {
      var KeyVal = Pairs[i].split('=');
      if ( ! KeyVal || KeyVal.length != 2 ) {continue;}
      var key = unescape( KeyVal[0] );
      var val = unescape( KeyVal[1] );
      val = val.replace(/\+/g, ' ');
      Params[key] = val;
   }
   return Params;
}

function tb_getPageSize(){
	var de = document.documentElement;
	var w = window.innerWidth || self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
	var h = window.innerHeight || self.innerHeight || (de&&de.clientHeight) || document.body.clientHeight;
	arrayPageSize = [w,h];
	return arrayPageSize;
}

function tb_detectMacXFF() {
  var userAgent = navigator.userAgent.toLowerCase();
  if (userAgent.indexOf('mac') != -1 && userAgent.indexOf('firefox')!=-1) {
    return true;
  }
}
jQuery.fn.accessNews = function(settings) {
	settings = jQuery.extend( {
		newsHeadline : "Top Stories",
		newsSpeed : "normal",
		num : 4 // nombre d'items ˆ afficher (4 par defaut)
	}, settings);
	return this.each( function(i) {
		aNewsSlider.init(settings, this);
	});
};

var aNewsSlider = {
	init : function(s, p) {
		itemWidth = Math.ceil($(p).width() / s.num);
		itemLength = jQuery("ul.first .item", p).length;
		newsContainerWidth = itemLength * itemWidth;
		jQuery(".container", p).css("width", newsContainerWidth + "px");
		if (itemLength > s.num)
			$(".next", p).show();
		else
			jQuery(".next", p).css("display","none");
		animating = false;
		jQuery(".next", p)
				.click(
						function() {
							itemWidth = Math.ceil($(p).width() / s.num);
							$(this).blur();
							if (animating == false) {
								animating = true;
								animateLeft = parseInt(jQuery(".container", p)
										.css("left"))
										- (itemWidth * s.num);
								if (animateLeft
										+ parseInt(jQuery(".container", p).css(
												"width")) > 0) {
									jQuery(".prev", p).css("display", "block");
									jQuery(".container", p)
											.animate(
													{
														left : animateLeft
													},
													s.newsSpeed,
													function() {
														jQuery(this).css(
																"left",
																animateLeft);
														if (parseInt(jQuery(
																".container", p)
																.css("left"))
																+ parseInt(jQuery(
																		".container",
																		p)
																		.css(
																				"width")) <= itemWidth
																* s.num) {
															jQuery(".next", p)
																	.css(
																			"display",
																			"none");
														}
														animating = false;
													});
								} else {
									animating = false;
								}
							}
							return false;
						});
		jQuery(".prev", p).click(
				function() {
					itemWidth = Math.ceil($(p).width() / s.num);
					$(this).blur();
					if (animating == false) {
						animating = true;
						animateLeft = parseInt(jQuery(".container", p).css(
								"left"))
								+ (itemWidth * s.num);
						if ((animateLeft + parseInt(jQuery(".container", p)
								.css("width"))) <= parseInt(jQuery(
								".container", p).css("width"))) {
							jQuery(".next", p).css("display", "block");
							jQuery(".container", p).animate(
									{
										left : animateLeft
									},
									s.newsSpeed,
									function() {
										jQuery(this).css("left", animateLeft);
										if (parseInt(jQuery(".container", p)
												.css("left")) == 0) {
											jQuery(".prev", p).css("display",
													"none");
										}
										animating = false;
									});
						} else {
							animating = false;
						}
					}
					return false;
				});
	}
};ï»¿/// <reference path="../../../lib/jquery-1.2.6.js" />
/*
	Masked Input plugin for jQuery
	Copyright (c) 2007-2009 Josh Bush (digitalbush.com)
	Licensed under the MIT license (http://digitalbush.com/projects/masked-input-plugin/#license) 
	Version: 1.2.2 (03/09/2009 22:39:06)
*/
(function($) {
	var pasteEventName = ($.browser.msie ? 'paste' : 'input') + ".mask";
	var iPhone = (window.orientation != undefined);

	$.mask = {
		//Predefined character definitions
		definitions: {
			'9': "[0-9]",
			'a': "[A-Za-z]",
			'*': "[A-Za-z0-9]"
		}
	};

	$.fn.extend({
		//Helper Function for Caret positioning
		caret: function(begin, end) {
			if (this.length == 0) return;
			if (typeof begin == 'number') {
				end = (typeof end == 'number') ? end : begin;
				return this.each(function() {
					if (this.setSelectionRange) {
						this.focus();
						this.setSelectionRange(begin, end);
					} else if (this.createTextRange) {
						var range = this.createTextRange();
						range.collapse(true);
						range.moveEnd('character', end);
						range.moveStart('character', begin);
						range.select();
					}
				});
			} else {
				if (this[0].setSelectionRange) {
					begin = this[0].selectionStart;
					end = this[0].selectionEnd;
				} else if (document.selection && document.selection.createRange) {
					var range = document.selection.createRange();
					begin = 0 - range.duplicate().moveStart('character', -100000);
					end = begin + range.text.length;
				}
				return { begin: begin, end: end };
			}
		},
		unmask: function() { return this.trigger("unmask"); },
		mask: function(mask, settings) {
			if (!mask && this.length > 0) {
				var input = $(this[0]);
				var tests = input.data("tests");
				return $.map(input.data("buffer"), function(c, i) {
					return tests[i] ? c : null;
				}).join('');
			}
			settings = $.extend({
				placeholder: "_",
				completed: null
			}, settings);

			var defs = $.mask.definitions;
			var tests = [];
			var partialPosition = mask.length;
			var firstNonMaskPos = null;
			var len = mask.length;

			$.each(mask.split(""), function(i, c) {
				if (c == '?') {
					len--;
					partialPosition = i;
				} else if (defs[c]) {
					tests.push(new RegExp(defs[c]));
					if(firstNonMaskPos==null)
						firstNonMaskPos =  tests.length - 1;
				} else {
					tests.push(null);
				}
			});

			return this.each(function() {
				var input = $(this);
				var buffer = $.map(mask.split(""), function(c, i) { if (c != '?') return defs[c] ? settings.placeholder : c });
				var ignore = false;  			//Variable for ignoring control keys
				var focusText = input.val();

				input.data("buffer", buffer).data("tests", tests);

				function seekNext(pos) {
					while (++pos <= len && !tests[pos]);
					return pos;
				};

				function shiftL(pos) {
					while (!tests[pos] && --pos >= 0);
					for (var i = pos; i < len; i++) {
						if (tests[i]) {
							buffer[i] = settings.placeholder;
							var j = seekNext(i);
							if (j < len && tests[i].test(buffer[j])) {
								buffer[i] = buffer[j];
							} else
								break;
						}
					}
					writeBuffer();
					input.caret(Math.max(firstNonMaskPos, pos));
				};

				function shiftR(pos) {
					for (var i = pos, c = settings.placeholder; i < len; i++) {
						if (tests[i]) {
							var j = seekNext(i);
							var t = buffer[i];
							buffer[i] = c;
							if (j < len && tests[j].test(t))
								c = t;
							else
								break;
						}
					}
				};

				function keydownEvent(e) {
					var pos = $(this).caret();
					var k = e.keyCode;
					ignore = (k < 16 || (k > 16 && k < 32) || (k > 32 && k < 41));

					//delete selection before proceeding
					if ((pos.begin - pos.end) != 0 && (!ignore || k == 8 || k == 46))
						clearBuffer(pos.begin, pos.end);

					//backspace, delete, and escape get special treatment
					if (k == 8 || k == 46 || (iPhone && k == 127)) {//backspace/delete
						shiftL(pos.begin + (k == 46 ? 0 : -1));
						return false;
					} else if (k == 27) {//escape
						input.val(focusText);
						input.caret(0, checkVal());
						return false;
					}
				};

				function keypressEvent(e) {
					if (ignore) {
						ignore = false;
						//Fixes Mac FF bug on backspace
						return (e.keyCode == 8) ? false : null;
					}
					e = e || window.event;
					var k = e.charCode || e.keyCode || e.which;
					var pos = $(this).caret();

					if (e.ctrlKey || e.altKey || e.metaKey) {//Ignore
						return true;
					} else if ((k >= 32 && k <= 125) || k > 186) {//typeable characters
						var p = seekNext(pos.begin - 1);
						if (p < len) {
							var c = String.fromCharCode(k);
							if (tests[p].test(c)) {
								shiftR(p);
								buffer[p] = c;
								writeBuffer();
								var next = seekNext(p);
								$(this).caret(next);
								if (settings.completed && next == len)
									settings.completed.call(input);
							}
						}
					}
					return false;
				};

				function clearBuffer(start, end) {
					for (var i = start; i < end && i < len; i++) {
						if (tests[i])
							buffer[i] = settings.placeholder;
					}
				};

				function writeBuffer() { return input.val(buffer.join('')).val(); };

				function checkVal(allow) {
					//try to place characters where they belong
					var test = input.val();
					var lastMatch = -1;
					for (var i = 0, pos = 0; i < len; i++) {
						if (tests[i]) {
							buffer[i] = settings.placeholder;
							while (pos++ < test.length) {
								var c = test.charAt(pos - 1);
								if (tests[i].test(c)) {
									buffer[i] = c;
									lastMatch = i;
									break;
								}
							}
							if (pos > test.length)
								break;
						} else if (buffer[i] == test[pos] && i!=partialPosition) {
							pos++;
							lastMatch = i;
						} 
					}
					if (!allow && lastMatch + 1 < partialPosition) {
						input.val("");
						clearBuffer(0, len);
					} else if (allow || lastMatch + 1 >= partialPosition) {
						writeBuffer();
						if (!allow) input.val(input.val().substring(0, lastMatch + 1));
					}
					return (partialPosition ? i : firstNonMaskPos);
				};

				if (!input.attr("readonly"))
					input
					.one("unmask", function() {
						input
							.unbind(".mask")
							.removeData("buffer")
							.removeData("tests");
					})
					.bind("focus.mask", function() {
						focusText = input.val();
						var pos = checkVal();
						writeBuffer();
						setTimeout(function() {
							if (pos == mask.length)
								input.caret(0, pos);
							else
								input.caret(pos);
						}, 0);
					})
					.bind("blur.mask", function() {
						checkVal();
						if (input.val() != focusText)
							input.change();
					})
					.bind("keydown.mask", keydownEvent)
					.bind("keypress.mask", keypressEvent)
					.bind(pasteEventName, function() {
						setTimeout(function() { input.caret(checkVal(true)); }, 0);
					});

				checkVal(); //Perform initial check for existing values
			});
		}
	});
})(jQuery);function buildUrlFromForm(formId) {
	alert("form=" + $("#" + formId +" input").fieldSerialize());
}

function initDynamicBlock(listNames, listUrls, listLinkNames, listLinkHRef) {
	for (i=0;i<listNames.length;i++) {
		$("#block_dynamic").append("<div id=\"dynamic_block_" + i + "\"></div>")
		if (listLinkNames[i] == "")
			blockAjax(listUrls[i], "dynamic_block_" + i, listNames[i]);
		else
			blockAjaxWithTitle(listUrls[i], "dynamic_block_" + i, listNames[i], listLinkNames[i], listLinkHRef[i]);
	}
}

function fixSeeMoreOnBlockAjax(bloc, functionOnClick,id,text) {
	a = $("#a_see_more_"+bloc);
	a.unbind();
	a.click(functionOnClick);
	a.id = id;
	a.text = text;
}

function blockAjax(url, bloc, divtitle){
	$("#"+bloc).html('<div class="blkPaint"><h2><div id="a_seemore_'+bloc+'"></div>'+divtitle+'</h2><div class="covers">  <center><img src="' + basedir + '/img/ajax-loader.gif" /> </center></div></div>')
	
	$.ajax({
		type: "GET", 
		url: url,
		timeout: 500000,
		error: function(){
			$("#" + bloc).html('<div class="blkPaint"><h2><div id="a_seemore_'+bloc+'"></div>'+divtitle+'</h2><div class="covers"><center> Erreur Technique </center> </div></div>')
		},
		success: function(retour){
			
			$("#" + bloc).html('<div class="blkPaint"><h2><div id="a_seemore_'+bloc+'"></div>'+divtitle+'</h2>' + retour + '</div>');
			$("#" + bloc).find('a.thickbox').bind('click', function(){
			  	var t = this.title || this.name || null;
			  	var a = this.href || this.alt;
			  	var g = false;
				tb_show(t,a,g);
				return false;
			});
			
			try{
				$(".sliderNouveautes, .sliderPlaylists").accessNews( {
					newsHeadline :"",
					newsSpeed :"normal"
				});
		
				$(".sliderConcerts").accessNews( {
					newsHeadline :"",
					newsSpeed :"normal",
					num:3
				});
			}catch (e) {}
			
			
			applyTooltipEvent("#"+bloc);
			applyPlayCssEventClick("#"+bloc);

		}
	});
	return false;
}

function blockAjaxWithTitle(url, bloc, divtitle, linkname, linkurl){
	$("#"+bloc).html('<div class="blkPaint"><h2><a href="' + linkurl + '.action">' + linkname + '</a>'+divtitle+'</h2><div class="covers">  <center><img src="' + basedir + '/img/ajax-loader.gif" /> </center></div></div>')
	
	$.ajax({
		type: "GET", 
		url: url,
		timeout: 500000,
		error: function(){
			$("#" + bloc).html('<div class="blkPaint"><h2><a href="' + linkurl + '.action">' + linkname + '</a>'+divtitle+'</h2><div class="covers"><center> Erreur Technique </center> </div></div>')
		},
		success: function(retour){
			$("#" + bloc).html('<div class="blkPaint"><h2><a href="' + linkurl + '.action">' + linkname + '</a>'+divtitle+'</h2>' + retour + '</div>');
			$("#" + bloc).find('a.thickbox').bind('click', function(){
			  	var t = this.title || this.name || null;
			  	var a = this.href || this.alt;
			  	var g = false;
				tb_show(t,a,g);
				return false;
			});
			
			try{
				$(".sliderNouveautes, .sliderPlaylists").accessNews( {
					newsHeadline :"",
					newsSpeed :"normal"
				});
		
				$(".sliderConcerts").accessNews( {
					newsHeadline :"",
					newsSpeed :"normal",
					num:3
				});
			}catch (e) {}
			
			
			applyTooltipEvent("#"+bloc);
			applyPlayCssEventClick("#"+bloc);

		}
	});
	return false;
}


function reordonneModules(listModule, conteneurId) {

	// listModule : string --> contient la liste des index de Module dans l'ordre voulu, sÃ©parÃ© par des point-virgules
	// conteneurId : string --> id du conteneur oÃ¹ insÃ©rer les modules
	
	var tabIndex = listModule.split(";");
	var nbModule = tabIndex.length;
	var resultHTML = "";
	var searchHasResults = false;
	
	for (var i=0; i<nbModule; i++ )
	{
		if(tabIndex[i] != "")
		{
			if($("#module-"+tabIndex[i]).html() != null)
			{
				resultHTML += "<div class=\"moduleList\" id=\"module-"+tabIndex[i]+"\">" + $("#module-"+tabIndex[i]).html() + "</div>";
				searchHasResults = true;
			}
		}
	}
	
	// si on n'a pas des resultats on ne passe pas le div avec id=conteneurId en show() sinon sous IE7 on affiche une barre blanche
	if(searchHasResults) {
		$("#"+conteneurId).html(resultHTML);
		$("#"+conteneurId).show();
		
		// fix mire layer
		$('a.authent').sfrLoginOverlay({
			padding:0,
			overlayOpacity:0.8,
			overlayColor:'#000'
		});
	}
};


// cree les parametre necessaire au fonctionnement de l autcompletion jslider
// retour un object
// ex : $("#keyword").autocomplete("${amfUrl}/search-autocomplete.action", makeAutoCompletionParamObject("#keyword","$('#keywordType').val();"));

// ATTENTION : le parametre searchType doit Ãªtre une expression qui sera execute par eval.

function makeAutoCompletionParamObject (inputTextId, searchType)
{
	var result = {
			matchSubset: false,
			minChars: 3,
			max: 15,
			extraParams : {keywordType: function() { return eval(searchType) }},
			highlight: false,
			scroll: true,
			scrollHeight: 300,
			autoFill: false,
			selectFirst: false,				
			formatItem: function(data, i, n, value) {
				
				var values = value.split(";;");
				var resultat = "";
				if(values.length > 0)
				{
					if(values[0] == "Artiste(s)" || values[0] == "Album(s)" || values[0] == "Single(s)" || values[0] == "Autre(s)"){
						resultat = "<table width=\"100%\"><tr><td class=\"titre\">"+values[0]+"</td></tr></table>";
					}
					else{
						if(values[2] == "artist")
							resultat = "<table width=\"100%\" class=\"resultats\"><tr><td>"+truncate(values[0], 25)+"</td>";
						else if(values[2] == "album")
							resultat = "<table width=\"100%\" class=\"resultats\"><tr><td >"+truncate(values[0], 25)+"</td>";
						else if(values[2] == "single")
							resultat = "<table width=\"100%\" class=\"resultats\"><tr><td>"+truncate(values[0], 25)+"</td>";
						else
							resultat = "<table width=\"100%\" class=\"resultats\"><tr><td>"+truncate(values[0], 25)+"</td>";
						if(values.length > 1) {
							resultat += "<td style=\"text-align:right;padding-right:20px;\">"+	values[1]+" rÃ©sultat(s)</td></tr></table>";
						}
						else
							resultat += "</tr></table>";
					}					
				}
				return (resultat != "") ? resultat:false;

			},

			formatResult: function(data, value) {
				var values = value.split(";;");
				var resultat = "";
				//if(values.length > 0)
				//{
				//	resultat = values[0];
				//}

				
				return (resultat != "") ? resultat:false;
			}
			
	}
	
	return result;
	
	
}


function makeParam(listParams) {

	// ListParams : array --> contient la liste des parametres dont on doit faire un chaine de parametre GET,
	// chaque element du tableau est construit de la faÃ§on suivante nomduparametre:valeur
	var nbparams = listParams.length;
	var result = "";
	
	for (var i=0; i<nbparams; i++ )
	{
		var couple = listParams[i].split(":");
		
		if(couple.length > 1)
		{
			if(couple[0] != '')
			{
				result += "&" + couple[0] + "=" + escape(couple[1]);
			}
		}
		
	}
	
	return result;

};

function minimizeMaximizeModule(index, bool) {

	if(bool)
	{
		$("#lienPlus-"+index).hide();
		$("#lienMoins-"+index).show();
		$(".storedPart-"+index).show();
	}else
	{
		$("#lienPlus-"+index).show();
		$("#lienMoins-"+index).hide();
		$(".storedPart-"+index).hide();
	}
};

function isValidNumberPhone(phoneNum) {
	var regExpObj = /06\d{8}/;
	   
	if(regExpObj.exec(phoneNum) == null) {
		return false;
	}
	else {
		return true;
	}
};

/* truncate the specified string (adding '...' at the end of truncated strings)
used when building autoComplete results (see makeAutoCompletionParamObject())
The troncature() function doesn't seem to do the correct job...
*/
function truncate(str, maxLength)
{
	return (str.length > maxLength) ? (str.substring(0, maxLength-3) + '...') : str;
}


function troncature(chaine, nbChar, suffixe) {
	// Tronque la chaine de caractere "chaine" Ã  un nombre de lettre donnÃ©es (nbChar) et ajout le suffixe.
	// La fonction conserve les mots entiers.

	var tabMots = chaine.split(" ");
	var nbMots = tabMots.length; 
	var nbCharCumul = 0;
	var result = "";
	
	if(nbMots>1)
	{
		for(var i=0; i<nbMots; i++)
		{
			nbCharCumul += tabMots[i].length;
			if(nbCharCumul < nbChar)
			{
				result += tabMots[i]+" ";
			}else
			{
				result += suffixe;
				break;
			}
		}
	}else
	{
		if(chaine.length>nbChar)
		{
			result = chaine.substring(0,nbChar);
			result += suffixe;
		}else
		{
			result = chaine;
		}
	}
	
	return result;
};


function loadModuleContent(actionUrl, idModule, indexContent, opened, otherParams) {
	
	
	otherParams = (otherParams != "") ? "&"+otherParams:"";
	
	$("#ajax-" + indexContent).height($("#range-" + indexContent).height()).toggle();
	$("#range-" + indexContent).toggle();
	
	
	$.ajax({
		url: actionUrl,
		type: 'GET',
		data: "id=" + idModule + otherParams,
		timeout: 50000,
		error: function(){
			$("#ajax-" + indexContent).height($("#range-" + indexContent).height()).toggle();
			$("#range-" + indexContent).html("Un incident technique s'est produit, nous mettons tout en oeuvre pour rÃ©tablir le bon fonctionnement du site.");

		},
	success: function(xml){
		$("#range-" + indexContent).toggle();
		$("#ajax-" + indexContent).toggle();

		var result = ($(xml).filter("#module-" + indexContent)).children();
		
		$("#module-" + indexContent).html(result);
		
		applyTooltipEvent('#module-'+indexContent);
		applyPlayCssEventClick('#module-'+indexContent);
		minimizeMaximizeModule(indexContent,opened);
		
		if(opened)
		{
			var page = $("#module-" + indexContent + " .pageCourante").text();
			var nbPage = $("#module-" + indexContent + " .pageTotal").text();
			
			if((page != undefined) && (nbPage != undefined))
			{
				applyPaginationSlider('sliderPagination-' + indexContent, page, nbPage);
			}
		}
		
		tb_reset();

		}
	});
	
};


function loadCodePromoResult(actionUrl, codePromo, conteneurId) {
	
	
	$.ajax({
		url: actionUrl,
		type: 'POST',
		data: "code=" + codePromo,
		timeout: 50000,
		error: function(){
			$("#" + conteneurId).html("Un incident technique s'est produit, nous mettons tout en oeuvre pour rÃ©tablir le bon fonctionnement du site.");
		},
	success: function(xml){
			var result = ($(xml).filter("#" + conteneurId)).children();
			$("#" + conteneurId).html(result);
		}
	});
	
};



function largeur_fenetre()
{
	 if (window.innerWidth) return window.innerWidth;
	 else if (document.body && document.body.offsetWidth) return document.body.offsetWidth;
	 else return 0;
}

function hauteur_fenetre()
{
	 if (window.innerHeight) return window.innerHeight  ;
	 else if (document.body && document.body.offsetHeight) return document.body.offsetHeight;
	 else return 0;
}

function achatFromFlash (pidProduit,pTypeProduit)
{  
	var chemin = amfURL+"/telecharger/acheter/confirmation.action?casdomain=amf-layer&productId="+pidProduit+"&productType="+pTypeProduit+"&partnerId=BOUTIQUE";
	
	if(developpement) {
		window.location.href = chemin;
	}
	else{
		$('a#sfrLoginOverlayFB').attr('href',chemin); 

		if(window.sfrParams.authenticated){
			window.location.href = chemin;
		}else{
			$('a#sfrLoginOverlayFB').trigger('click');
		}
		
	}
}


function playVideo(pUrl, pTitre, pArtiste, pDuree, pAnnee)
{
	if(pUrl)
	{
		if(!pTitre)
		{
			pTitre="";
		}
		
		if(!pArtiste)
		{
			pArtiste="";
		}
		
		if(!pDuree)
		{
			pDuree="";
		}
		
		if(!pAnnee)
		{
			pAnnee="";
		}
		
		
		var chemin = basedir + "/includes/players/videoplayer.jsp?url=" + pUrl + "&title=" + pTitre + "&artiste=" + pArtiste + "&duree=" + pDuree + "&annee=" + pAnnee + "&keepThis=true&p=ok&TB_iframe=true&height=450&width=450";
		tb_show("", chemin, false);
	}
}


/*********************************************/



/***********  P L A Y E R   M P 3  ***********/
function getAppName(flexApp) {
	if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)){
		return window[flexApp];
	}
	else {
		return window.document[flexApp];
	}
}
function stopAllSounds(){
	if(getAppName("mediaRunner"))
	{
		getAppName("mediaRunner").flashScript_Stop();
	}
}

function playMedia(pTypeInterface, pUrl, pTitre, pArtiste, pDuree, pAnnee) {

	// pTypeInterface : 'audio' ou 'video', il s'agit du type d'interface a lancer.
	// pUrl : url du fichier a lire
	// pTitre (FACULTATIF)
	// pArtiste (FACULTATIF)
	// pDuree (FACULTATIF)
	// pAnnee (FACULTATIF)
	
	
	if((pTypeInterface)&&(pUrl))
	{
		
		if(!pTitre)
		{
			pTitre="";
		}
		
		if(!pArtiste)
		{
			pArtiste="";
		}
		
		if(!pDuree)
		{
			pDuree="";
		}
		
		if(!pAnnee)
		{
			pAnnee="";
		}
		
		
		if(getAppName("banner10"))
		{
			getAppName("banner10").flashScript_Stop();
		}
		
		
		
		switch (pTypeInterface)
		{
			case 'audio':
				
				if(getAppName("mediaRunner"))
				{
					getAppName("mediaRunner").flashScript_Play(pUrl);
				}else
				{
					flash_AudioComplete();
				}

				break;
			case 'video':
				stopAllSounds();
				playVideo(pUrl,pTitre,pArtiste,pDuree,pAnnee);
				flash_AudioComplete();
				break;
		}
	}
	
	return false;
	
}

function flash_Alert(m)
{
	alert(m);
}

function flash_AudioComplete()
{

	removeAllPauseButton();
	removeAllArreterButton();
}


function removeAllPauseButton()
{
	$('a.stop').addClass('play');
	$('a.stop').removeClass('stop');
	$("a.play").unbind('click')
	$("a.play").click(function() {
		applyCssAfterClickOnPlay($(this));
	});
}



function applyPaginationSlider(idPaginationSlider, pagecourante, nbpage){
	
	$("#"+idPaginationSlider+" .ui-slider").slider({
		steps: nbpage,
		minValue: 1,
		maxValue: nbpage,
		startValue: pagecourante,
		values: [],
		slide: function(e, ui) { 
			$("#" + idPaginationSlider + " .infoPagination .pageCourante").html(ui.slider.curValue+1);
		}
	
	});
}


function applyPlayCssEventClick(conteneur){
	
	// Si le conteneur est prÃ©cisÃ©, on appliquera l'Ã©venement qu'au contenu de celui-ci
	// Sinon on l'applique Ã  toute la page
	
	if(!conteneur)
	{
		conteneur = "";
	}else
	{
		conteneur+=" ";
	}

	
	$(conteneur+".play").click(function() {
		applyCssAfterClickOnPlay($(this));
	});


	$(conteneur+".stop").click(function() {
		applyCssAfterClickOnStop($(this));
	});
	
	
	$(".ecouter").click(function() {
		applyCssAfterClickOnEcouter($(this));
	});

	$(".arreter").click(function() {
		applyCssAfterClickOnArreter($(this));
	});
	
}

function applyCssAfterClickOnPlay(o) {
	
	if(getAppName("mediaRunner"))
	{
		removeAllArreterButton();
		$('.stop').addClass('play');
		$('.stop').removeClass('stop');
		o.removeClass('play');
		o.addClass('stop');
		o.unbind('click');
		o.click(function() {
			applyCssAfterClickOnStop($(this));
		});
	}
}

function applyCssAfterClickOnStop(o) {
	if(getAppName("mediaRunner"))
	{
		o.removeClass('stop');
		o.addClass('play');
		o.unbind('click');
		o.click(function() {
			applyCssAfterClickOnPlay($(this));
		});
	}
}


function applyCssAfterClickOnEcouter(o) {

	if(getAppName("mediaRunner"))
	{
		removeAllPauseButton();
		o.removeClass('ecouter');
		o.addClass('arreter');
		o.unbind('click');
		o.click(function() {
			applyCssAfterClickOnArreter($(this));
		});
	}
}

function applyCssAfterClickOnArreter(o) {
	if(getAppName("mediaRunner"))
	{
		o.removeClass('arreter');
		o.addClass('ecouter');
		o.unbind('click');
		o.click(function() {
			applyCssAfterClickOnEcouter($(this));
		});
	}
}

function removeAllArreterButton() {

	$('.arreter').addClass('ecouter');
	$('.arreter').removeClass('arreter');
	$(".ecouter").unbind('click');
	$(".ecouter").click(function() {
		applyCssAfterClickOnEcouter($(this));
	});
	
	if(getAppName("banner10"))
	{
		getAppName("banner10").flashScript_Stop();
	}
}



function applyTriCssEventClick(){
	
	if (!(jQuery.browser.msie && jQuery.browser.version < 7)) { 
	
		
		$("a.icoTriAlpha.off").click(function() {
			applyTriFuntionAfterClick($(this))
		});
		
		$("a.icoTriDate.off").click(function() {
			applyTriFuntionAfterClick($(this))
		});
		
		$("a.icoTriPop.off").click(function() {
			applyTriFuntionAfterClick($(this))
		});
	
	}
}

function applyTriFuntionAfterClick(o) {
	if (!(jQuery.browser.msie && jQuery.browser.version < 7)) { 
		
		o.unbind('click');

		o.parent("div").children("a").removeClass("on");
		o.parent("div").children("a").addClass("off");
		
		o.addClass("on");
		o.removeClass("off");

		applyTriCssEventClick();
	}
}

/***
 * 
 * returns true if iframe's current href is on the same domain of parent document, false otherwise
 * 
 * NOTE: as of today, it works on IE7, FF 3.5+, Chrome 4+, Opera 10.5+ but as it relies
 * 		 on some hacks it could stop working with future versions...
 * ***/
function isSameDomain(iframeID)
{
	var sameDomain = false;

	try	// Other browsers simply return undefined (working browsers) or unkown (IE: wtf ??) when accessing contentWindow from another Domain
	{
		if ((typeof $(iframeID).get(0).contentWindow.location.href !== 'unknown') && (typeof $(iframeID).get(0).contentWindow.location.href !== 'undefined'))
		{
			sameDomain = true;
		}
	}
	catch(e) // FF will throw a security exception when trying to access contentWindow from another doamin
	{
		sameDomain = false;
	}
		return sameDomain;
}
/*** /Nico: Test... ***/

/**
 * fonction d'animation du bloc top vente single/album
 */
function initAnimationTopVentes() {
	jQuery('div.onglet').click( function () {
		
		// fonction utilitaire
		function toggleContentType(id) {
			var prefix = 'content_';
			if(id == prefix + 'single') {
				return prefix + 'album';
			}
			if(id == prefix + 'album') {
				return prefix + 'single';
			}
		
		}
		
		// modif bouton onglet
		jQuery('.on').removeClass('on');
		jQuery(this).addClass('on');
		
		// modif contenu affiche
		var newContentType = $(this).attr('title');
		jQuery('#' + toggleContentType(newContentType)).hide();
		jQuery('#' + newContentType).fadeIn('fast');
    });
}	//Definition d un tableau
	var tabOnglet = new Array();
	var typeOrderAffiche = "ASC";
	var enumOrderAffiche = "CHRONO";
		
	function downloadMobile(idTransaction,idProduit,productType) {
		
			$.ajax({
			    url: 'mes-achats/sendWappush.action',
			    type: 'GET',
			    data: "transactionId="+idTransaction+"&productId="+idProduit+"&productType="+productType,
				timeout: 5000,
			    error: function(){
			        alert("Nous n'avons pas pu vous envoyer de SMS. Veuillez rÃ©essayer dans quelques instants. ");
			    },
			    success: function(xml){
			    }
			});
	}
		
				
	function changeSort(typeEnum,orderEnum,type,offset) {
		launchRequest(typeEnum,orderEnum,type,offset)	
	}

	function next(typeEnum,orderEnum,type,offset) {
		launchRequest(typeEnum,orderEnum,type,(offset*1)+10);
	}

	function before(typeEnum,orderEnum,type,offset) {
		launchRequest(typeEnum,orderEnum,type,(offset*1)-10);
	}
function applyTooltipEvent(conteneur){
	
	var ie6Enabled = false;
	
	if((ie6Enabled) || (!(jQuery.browser.msie && jQuery.browser.version < 7)))
	{
	
		// Si le conteneur est prÃ©cisÃ©, on appliquera l'Ã©venement tooltip qu'au contenu de celui-ci
		// Sinon on l'applique Ã  toute la page
		
		if(!conteneur)
		{
			conteneur = "";
		}else
		{
			conteneur+=" ";
		}
	
		// Suppression de toutes les infobulles prÃ©existante
		
		$(conteneur+".producttooltipenabled").removeAttr("title");
		$(conteneur+".producttooltipenabled").removeAttr("alt");
		
		$(conteneur+".producttooltipenabled a").removeAttr("title");
		$(conteneur+".producttooltipenabled a").removeAttr("alt");
		
		$(conteneur+".producttooltipenabled img").removeAttr("title");
		$(conteneur+".producttooltipenabled img").removeAttr("alt");
		
		//Ajout de l'infobulle jquery
		
		
		$(conteneur+".standardtooltipenabled").tooltip({
			showURL: false,
			delay:200,
			track:true,
			bodyHandler: function() {
				var legend = $(this).find('span').text();
				var type = $(this).find('p').text();
				
				var longueurTooltip = (legend.length > 50) ? 300:legend.length*7;
				
				var result = "";
				
				if(legend != undefined && legend != "")
				{
					result = $('<div/>').css({'width': longueurTooltip+'px'}).addClass('tooltipStandardContent').append('<div class=\'type\'>' + type + '</div>' + '<div class=\'info\'>' + legend + '</div>');
				}
				return result;
				
			}
		});
		
		
		$(conteneur+".producttooltipenabled").tooltip({
										showURL: false,
										delay:200,
										track:true,
										bodyHandler: function () { return generateProductToolTip($(this)) }
		});
	}
}



function generateProductToolTip(conteneur) {

		// Recuperation de l'id du conteneur dans lequel se trouvent les informations Ã  afficher dans l'infobulle
		
		var attrClass = conteneur.attr("class");
		var tabSeparation = attrClass.split("tooltipsource");
		
		var template = 	"<div  class=\"tooltipContent\">" +
				"@@cover@@" +
				"<div class=\"type\">@@type@@</div>" +
				"<div class=\"info\">" +
				"@@duration@@" +
				"@@artiste@@" +
				"@@titre@@" +
				"@@price@@" +
				"@@format@@" +
				"</div>" +
				"</div>";
		
		if(tabSeparation.length > 1)
		{
			var tabSeparation2 = tabSeparation[1].split(" ");
			var tooltipsource = $('#tooltip'+tabSeparation2[0]).html();
			
			// Chaque information se trouve dans une balise li, sous la forme clÃ©:valeur
			// On transforme cela en un objet InfoProduct
			
			var tabInfo = $(tooltipsource).find("li");
			var nbInfo = tabInfo.length;
			var InfoProduct = makeObjectWithKeyValue(tabInfo, ":")

			
			// Pour certaines infos, on s'assure qu'il n'y a pas d'espaces parasites
			
			InfoProduct.type = (InfoProduct.type != undefined) ? InfoProduct.type.replace(" ",""):"";
			InfoProduct.cover = (InfoProduct.cover != undefined) ? InfoProduct.cover.replace(" ",""):"";
			InfoProduct.duration = (InfoProduct.duration != undefined) ? InfoProduct.duration.replace(" ",""):"";
			InfoProduct.price = (InfoProduct.price != undefined) ? InfoProduct.price.replace(" ",""):"";
			
			// Traitement du contenu de l'objet InfoProduct, on place les infos dans le template.

			
			var result = template;
			var nbLignesInfo = 0;
			
			// TYPE
			if(InfoProduct.type)
			{
				switch(InfoProduct.type.toLowerCase())
				{
				case 'single':
					result = result.replace("@@type@@","Single");
					break;
				case 'album':
					result = result.replace("@@type@@","Album");
					break;
				case 'sonneriehypersound':
					result = result.replace("@@type@@","Sonnerie");
					break;
				case 'clip':
					result = result.replace("@@type@@","Clip");
					break;
				default:
					result = result.replace("@@type@@",InfoProduct.type);				
				}
				
			}else
			{
				result = result.replace("@@type@@","");
			}
			
			// VIGNETTE
			if(InfoProduct.cover)
			{
				result = result.replace("@@cover@@","<img src=\""+InfoProduct.cover+"\" height=\"80\" style=\"float:left;margin-right:5px;border:1px solid #AAAAAA\">");
				
			}else
			{
				result = result.replace("@@cover@@","");
			}
			
			// DUREE
			if(InfoProduct.duration)
			{

				var durationFormated = getMinutesFormatedDuration(InfoProduct.duration);
				result = result.replace("@@duration@@","<p>DurÃ©e : "+durationFormated+" min</p>");
				nbLignesInfo++;
				
			}else
			{
				result = result.replace("@@duration@@","");
			}

			
			// NOM DE L'ARTISTE
			if(InfoProduct.artiste)
			{
				result = result.replace("@@artiste@@","<p><em>Artiste</em> : "+troncature(InfoProduct.artiste,30,"...")+"</p>");
				nbLignesInfo++;
			}else
			{
				result = result.replace("@@artiste@@","");
			}
			
			// TITRE
			if(InfoProduct.titre)
			{
				result = result.replace("@@titre@@","<p><em>Titre</em> : "+troncature(InfoProduct.titre,30,"...")+"</p>");
				nbLignesInfo++;
			}else
			{
				result = result.replace("@@titre@@","");
			}
			
			// PRIX
			if(InfoProduct.price)
			{
				var infoPrix = "";
				
				if(InfoProduct.type)
				{
					if(InfoProduct.type.toLowerCase() == "single")
					{
						infoPrix = "(ou inclus dans votre forfait)";
					}
				}
				
				result = result.replace("@@price@@","<p><strong>Prix : "+(parseInt(InfoProduct.price)/100).toString()+" â‚¬</strong> "+ infoPrix +"</p>");
				nbLignesInfo++;
			}else
			{
				result = result.replace("@@price@@","");
			}


			// FORMAT que l'on affiche que pour les album, single et clip
			if((InfoProduct.format && InfoProduct.format != "" && InfoProduct.format != " ")&&((InfoProduct.type.toLowerCase() == "single")||(InfoProduct.type.toLowerCase() == "album")||(InfoProduct.type.toLowerCase() == "clip")))
			{
				var infoFormat = "";
				if(InfoProduct.format == "WMA")
				{
					infoFormat = "(protection anti-copie)";
					
				}else if(InfoProduct.format == "MP3")
				{
					infoFormat = "(compatible tous lecteurs MP3)";
				}

				result = result.replace("@@format@@","<p><span class=\"redLight\"><strong>Format : "+InfoProduct.format+"</strong></span> "+infoFormat+"</p>");
				nbLignesInfo++;
				
			}else
			{
				result = result.replace("@@format@@","");
			}

			//S'il n'y a pas de lignes a afficher, on n'affiche pas de tooltip
			
			if(nbLignesInfo == 0)
			{
				result = "";
			}
			
			// On autorise l'affiche du tooltip que pour certain type
			
			if((InfoProduct.type != "Single")&&(InfoProduct.type != "single")&&(InfoProduct.type != "Album")&&(InfoProduct.type != "album")&&(InfoProduct.type != "clip")&&(InfoProduct.type != "sonnerieHypersound"))
			{
				result = "";
			}
			
			return result;
		}
															
												
}


function makeObjectWithKeyValue(tab, separateur)
{

	
	var result = new Object();
	
	var nbInfo = tab.length;
	
	for(var i=0; i<nbInfo; i++)
	{
		var info = $(tab[i]).text();

		if(info!="")
		{
			
			var tabCouple = info.split(separateur);


			if(tabCouple.length >= 2)
			{
				result[tabCouple[0]] = tabCouple[1];
				$.each( tabCouple, function(i, n){
					if(i>1)
					{
						result[tabCouple[0]] += ':'+ n;
					}
				});
				
			}
			
		}
	}
	
	return result;

}

function getMinutesFormatedDuration(duration)
{
	//convertit les formats hh:mm:ss en mm:ss
	
	var result = duration;
	
	if(duration.length == 8)
	{
		var heures = duration.substring(0,2);
		var minutes = duration.substring(3,5);
		var secondes = duration.substring(6,8);
		
		result = ((heures*60)+(1*minutes)).toString() + ":" + secondes;
	}
	return result;
}
$(document).ready(function() {

	
	function getScrollPosition() { /* fonction qui retourne la position du scroll dans la page */
		return Array((document.documentElement && document.documentElement.scrollLeft) || window.pageXOffset || self.pageXOffset || document.body.scrollLeft,(document.documentElement && document.documentElement.scrollTop) || window.pageYOffset || self.pageYOffset || document.body.scrollTop);
	}

	function fixeMenu()
	{
		$('#scrollable').removeClass('off');
		$('#scrollable').removeClass('on');
		$('#scrollable').addClass('on');
	}

	function unFixeMenu()
	{
		$('#scrollable').removeClass('off');
		$('#scrollable').removeClass('on');
		$('#scrollable').addClass('off');
	}


	unFixeMenu();


	if((hauteur_fenetre() > 801) && (!jQuery.browser.msie)) {

		$(document).scroll(function() { /* on gere la position du scroll et on le rend fixe si c est necessaire */
			var positionScroll = getScrollPosition();
			if (parseInt(positionScroll[1]) > 211) {
				fixeMenu();
			}
			else {
				unFixeMenu();
			}
		});

	}

});function applySpotifyEventClick() {
	/*
	 * FONCTIONS PRESENTATION
	 */
	$('.has-tooltip').tooltip({
		delay:200,
		bodyHandler: function () {
			var template = 	"<div  class=\"spotifyTooltip\">" +
				"@@cover@@" +
				"<div class=\"info\">" +
				"@@artiste@@" +
				"@@titre@@" +
				"</div>" +
				"</div>";
			var result = template;
			var cover = $(this).children().children('img').attr('src');
			var title = $(this).children().children('img').attr('alt');

			if (cover) {
				result = result.replace("@@cover@@","<img src=\""+cover+"\" height=\"80\" style=\"float:left;margin-right:5px;border:1px solid #AAAAAA\">");
			} else {
				result = result.replace("@@cover@@","")
			}
			if (title) {
				var tab = title.split('|');
				var titre = tab[0];
				var artiste = tab[1];
				if (titre) {
					result = result.replace("@@titre@@","<p><em>Titre</em> : "+titre+"</p>");
				} else {
					result = result.replace("@@titre@@","");
				}
				if (artiste) {
					result = result.replace("@@artiste@@","<p><em>Artiste</em> : "+artiste+"</p>");
				} else {
					result = result.replace("@@artiste@@","");
				}
			}

			return result;
		}
	});

	$('#menu_spotify a').click(function() {
		$(this).parent().children().removeClass('active').removeClass('show');
		$(this).addClass('active');
		$('#body_spotify').children('div').removeClass('active');
		$('#body_spotify').children('div.' + $(this).attr('id')).addClass('active');
		$(this).parent().children('span.' + $(this).attr('id')).addClass('show');
	});

	$('.video_body_top_small').click(function() {
		$(this).parent().children('div').removeClass('active');
		$(this).parent().parent().children('div').removeClass('active');
		$(this).addClass('active');
		$(this).parent().parent().children('div.' + $(this).attr('id')).addClass('active');
	});

	$('.faq_body_left_text').click(function() {
		$(this).parent().children('div').removeClass('active');
		$(this).addClass('active');
		$(this).parent().parent().children('div#faq_body_right').children('div').removeClass('active');
		$('#faq_body_right').children('div.' + $(this).attr('id')).addClass('active');
	});

	$('#body_spotify a#ytimg').click(function() {
		var cssObj = {
	      'display' : 'block',
	      'opacity' : '0.8',
	      'background-color' : '#000000'
	    }
	    $('#bg-overlay').css(cssObj);
		$('#bg-overlay').show();
			cssObj = {
	      'position' : 'absolute',
	      'top' : '150px',
	      'left' : '150px'
	    }
	    $('#overlay').css(cssObj);
		$('#overlay').show();
	});

	$('#body_spotify .close').click(function() {
		$('#overlay').hide();
		$('#bg-overlay').hide();
	});

	$('#bg-overlay').click(function() {
		$('#overlay').hide();
		$('#bg-overlay').hide();
	});

	/*
	 * FONCTIONS SOUSCRIPTION
	 */
	$('#actionCompteSpotify').click( function() {
		$('div#contenuOffreSpotify').slideUp('slow');
		$('div#contenuCompteSpotify').slideToggle('slow');
		return false;
	});

	$('#actionRetourSpotify1').click( function() {
		$('#contenuCompteSpotify').slideToggle('slow', function() {
			$('div#ongletCompteSpotify').removeClass('onglet');
			$('div#ongletCompteSpotify').addClass('onglet2');
			$('div#ongletOffreSpotify').removeClass('onglet3');
			$('div#ongletOffreSpotify').addClass('onglet');
		});
		$('#contenuOffreSpotify').slideToggle('slow',function() {
			$('div#contenuOffreSpotify .suivant').show();
		});
		return false;
	});

	$('#actionRetourSpotify2').click( function() {
		$('#contenuCompteSpotify').slideUp('slow',function() {
			$('#creationCompteSpotify').hide();
			$('#loginSpotify').show();
			$('#contenuCompteSpotify').slideDown('slow');
		});
		return false;
	});

	$('#logonSpotify').click( function() {
		$('.loading').show();
		loginSpotifyAjax();
		return false;
	});

	$('#afficherCompteSpotify').click( function() {
		afficherCreerCompteSpotify();
		return false;
	});

	$('#creerCompteSpotify').click( function() {
		$('.loading').show();
		creerSpotifyCompte();
		return false;
	});

	$('#compte_birthdate').mask("99/99/9999");
	$('#compte_postalCode').mask("99999");

}

function afficherBlocActivationSpotify() {
	$('div#contenuCompteSpotify').slideUp('slow', function() {
		$('div#ongletCompteSpotify').removeClass('onglet');
		$('div#ongletCompteSpotify').addClass('onglet3');
	});
	$('div#contenuActivation').slideToggle('slow', function() {
		$('div#ongletActivation').removeClass('onglet2');
		$('div#ongletActivation').addClass('onglet');
	});
	$('#ongletCompteSpotify').unbind('click');
	$('.reflet_2').addClass('reflet_3');
	$('.reflet_2').removeClass('reflet_2');
};

function closeSpotify() {
	$('div#contenuActivation').slideUp('slow');
}

function closeNoEligibleSpotify() {
	$('div#contenuOffreSpotify').slideUp("slow");
}

function returnHome() {
	document.location.href="${pageContext.request.contextPath}/home.action";
}

function afficherCreerCompteSpotify() {
	$('#contenuCompteSpotify').slideUp('slow',function() {
		$('#loginSpotify').hide();
		$('#creationCompteSpotify').show();
		$('#contenuCompteSpotify').slideDown('slow');
	});
}

function loginSpotifyAjax() {
	var username = $('#login_username').val();
	var email = $('#login_email').val();
	$.ajax({
		url: 'spotifyLogin.action',
		type: 'POST',
		async : false,
		data : "username=" + username + "&email=" + email,
		timeout: 50000,
		error: function(){
			$('#erreurLogin').html('Votre compte n\'est pas valide : <span style=\"color:red;\">Login inexistant !</span>');
		},
		success: function(data){
			$('.loading').hide();
			if ($(data).filter('#eligible').val() != 'false') {
				if ($(data).filter('#login_msg').val() != 'success') {
					if($(data).filter('#error').val() == 'error') {
						$('#contenuOffreSpotify').html(data);
						$('#contenuOffreSpotify').css('background', 'none repeat scroll 0 0 #FFFFFF');
						$('#contenuCompteSpotify').slideToggle('slow', function() {
							$('div#ongletCompteSpotify').removeClass('onglet');
							$('div#ongletCompteSpotify').addClass('onglet2');
							$('div#ongletOffreSpotify').removeClass('onglet3');
							$('div#ongletOffreSpotify').addClass('onglet');
						});
						$('#contenuOffreSpotify').slideToggle('slow');
						return false;
					} else {
						var msg = 'Votre compte n\'est pas valide : <span style=\"color:red;\">' + $(data).filter('#login_msg').val();
						if ($(data).filter('#spotifyGetCredentialMessage').length) {
							msg += $(data).filter('#spotifyGetCredentialMessage').html();
						}
						msg += '</span>';
						
						$('#erreurLogin').html(msg);
						$("#username").css('border','1px solid black');
						document.getElementById("login_username").focus();
					}
				} else {
					$('#contenuActivation .detailActivation').html(data);
					afficherBlocActivationSpotify();
					return false;
				}
			} else {
				$('#contenuOffreSpotify').html(data);
				$('#contenuOffreSpotify').css('background', 'none repeat scroll 0 0 #FFFFFF');
				$('#contenuCompteSpotify').slideToggle('slow', function() {
					$('div#ongletCompteSpotify').removeClass('onglet');
					$('div#ongletCompteSpotify').addClass('onglet2');
					$('div#ongletOffreSpotify').removeClass('onglet3');
					$('div#ongletOffreSpotify').addClass('onglet');
				});
				$('#contenuOffreSpotify').slideToggle('slow');
				return false;
			}
		}
	});
}

function creerSpotifyCompte() {
	var username = $('#compte_username').val();
	var email = $('#compte_email').val();
	var password = $('#compte_password').val();
	var confirmPassword = $('#compte_confirmPassword').val();
	var birthday = $('#compte_birthdate').val();
	var postalCode = $('#compte_postalCode').val();
	var sexe = $('input[type=radio]:checked').val();
	var cgu = $('#cgu:checked').val();
	$.ajax({
		url: 'spotifyCreerCompte.action',
		type: 'POST',
		data : "username=" + username + "&email=" + email + "&password=" + password + "&confirmPassword=" + confirmPassword + "&birthdate=" + birthday + "&postalCode=" + postalCode + "&sexe=" + sexe + "&cgu=" + cgu,
		timeout: 50000,
		error: function(){
			return false;
		},
		success: function(data){
			$('.loading').hide();
			if ($(data).filter('#eligible').val() != 'false') {
				if ($(data).filter('#error').val() != 'success') {
					if ($(data).filter('#error').val() == 'error') {
						$('#contenuOffreSpotify').html(data);
						$('#contenuOffreSpotify').css('background', 'none repeat scroll 0 0 #FFFFFF');
						$('#contenuCompteSpotify').slideToggle('slow', function() {
							$('div#ongletCompteSpotify').removeClass('onglet');
							$('div#ongletCompteSpotify').addClass('onglet2');
							$('div#ongletOffreSpotify').removeClass('onglet3');
							$('div#ongletOffreSpotify').addClass('onglet');
						});
						$('#contenuOffreSpotify').slideToggle('slow');
						return false;
					} else {
						$('#erreurCompte').show();
						$('#erreurCompte').html('<div class="police">Votre compte n\'a pas pu &ecirc;tre cr&eacute;&eacute; : <span style=\"color:red;\">' + $(data).filter('#error').val() + '</span></div>');
					}
				} else {
					$('#contenuActivation .detailActivation').html(data);
					afficherBlocActivationSpotify();
					return false;
				}
			} else {
				$('#contenuOffreSpotify').html(data);
				$('#contenuOffreSpotify').css('background', 'none repeat scroll 0 0 #FFFFFF');
				$('#contenuCompteSpotify').slideToggle('slow', function() {
					$('div#ongletCompteSpotify').removeClass('onglet');
					$('div#ongletCompteSpotify').addClass('onglet2');
					$('div#ongletOffreSpotify').removeClass('onglet3');
					$('div#ongletOffreSpotify').addClass('onglet');
				});
				$('#contenuOffreSpotify').slideToggle('slow');
				return false;
			}
		}
	});
}

function spotifyPresentationAnchorsHandling() {
	var element = "#menu_spotify a" + window.location.hash;
	
	var refreshSpotifyMenu = function(element) {
		$(element).parent().children().removeClass('active').removeClass('show');
		$(element).addClass('active');
		$('#body_spotify').children('div').removeClass('active');
		$('#body_spotify').children('div.' + $(element).attr('id')).addClass('active');
		$(element).parent().children('span.' + $(element).attr('id')).addClass('show');
	};
	
	if ((window.location.hash != "") && ($(element).length >= 1)) {
		refreshSpotifyMenu(element);
	} else if (window.location.hash != "") {
		
		var menuElemClass = $('#body_spotify div').has(window.location.hash).first().attr('class');
		if (menuElemClass && (menuElemClass != "") && menuElemClass.split(' ').length > 0) {
			
			element = "#menu_spotify a#" + menuElemClass.split(' ')[0];
			refreshSpotifyMenu(element);
		
			var faqBodyRightClass = $('#faq_body_right div').has(window.location.hash).first().attr('class');
			if (faqBodyRightClass && (faqBodyRightClass != "") && faqBodyRightClass.split(' ').length > 1) {
				element = "#faq_body_left div#" + faqBodyRightClass.split(' ')[1];
				$(element).parent().children('div').removeClass('active');
				$(element).addClass('active');
				$(element).parent().parent().children('div#faq_body_right').children('div').removeClass('active');
				$('#faq_body_right').children('div.' + $(element).attr('id')).addClass('active');
			}

			window.location.hash = window.location.hash;
		}
	} 
}/*
* Fonction pour actualiser le compteur de la vente flash
* (appellÃ©e au document ready)
**/
function applyVenteFlashCountDown() {
	var vfEndDateStr = jQuery("#counterDfId").val();
	var vfEndDate = new Date(Number(vfEndDateStr));
    jQuery('#counterText').countdown({until: vfEndDate, compact: true, description: '', layout: '{dn}{dl} {hn}{hl} {mn}{ml} {sn}{sl}'});
}
      /* http://keith-wood.name/countdown.html
   Countdown for jQuery v1.5.9.
   Written by Keith Wood (kbwood{at}iinet.com.au) January 2008.
   Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and 
   MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses. 
   Please attribute the author if you use it. */

/* Display a countdown timer.
   Attach it with options like:
   $('div selector').countdown(
       {until: new Date(2009, 1 - 1, 1, 0, 0, 0), onExpiry: happyNewYear}); */

(function($) { // Hide scope, no $ conflict

/* Countdown manager. */
function Countdown() {
	this.regional = []; // Available regional settings, indexed by language code
	this.regional[''] = { // Default regional settings
		// The display texts for the counters
		labels: ['Years', 'Months', 'Weeks', 'Days', 'Hours', 'Minutes', 'Seconds'],
		// The display texts for the counters if only one
		labels1: ['Year', 'Month', 'Week', 'Day', 'Hour', 'Minute', 'Second'],
		compactLabels: ['y', 'm', 'w', 'd'], // The compact texts for the counters
		whichLabels: null, // Function to determine which labels to use
		timeSeparator: ':', // Separator for time periods
		isRTL: false // True for right-to-left languages, false for left-to-right
	};
	this._defaults = {
		until: null, // new Date(year, mth - 1, day, hr, min, sec) - date/time to count down to
			// or numeric for seconds offset, or string for unit offset(s):
			// 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds
		since: null, // new Date(year, mth - 1, day, hr, min, sec) - date/time to count up from
			// or numeric for seconds offset, or string for unit offset(s):
			// 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds
		timezone: null, // The timezone (hours or minutes from GMT) for the target times,
			// or null for client local
		serverSync: null, // A function to retrieve the current server time for synchronisation
		format: 'dHMS', // Format for display - upper case for always, lower case only if non-zero,
			// 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds
		layout: '', // Build your own layout for the countdown
		compact: false, // True to display in a compact format, false for an expanded one
		significant: 0, // The number of periods with values to show, zero for all
		description: '', // The description displayed for the countdown
		expiryUrl: '', // A URL to load upon expiry, replacing the current page
		expiryText: '', // Text to display upon expiry, replacing the countdown
		alwaysExpire: false, // True to trigger onExpiry even if never counted down
		onExpiry: null, // Callback when the countdown expires -
			// receives no parameters and 'this' is the containing division
		onTick: null, // Callback when the countdown is updated -
			// receives int[7] being the breakdown by period (based on format)
			// and 'this' is the containing division
		tickInterval: 1 // Interval (seconds) between onTick callbacks
	};
	$.extend(this._defaults, this.regional['']);
	this._serverSyncs = [];
}

var PROP_NAME = 'countdown';

var Y = 0; // Years
var O = 1; // Months
var W = 2; // Weeks
var D = 3; // Days
var H = 4; // Hours
var M = 5; // Minutes
var S = 6; // Seconds

$.extend(Countdown.prototype, {
	/* Class name added to elements to indicate already configured with countdown. */
	markerClassName: 'hasCountdown',
	
	/* Shared timer for all countdowns. */
	_timer: setInterval(function() { $.countdown._updateTargets(); }, 980),
	/* List of currently active countdown targets. */
	_timerTargets: [],
	
	/* Override the default settings for all instances of the countdown widget.
	   @param  options  (object) the new settings to use as defaults */
	setDefaults: function(options) {
		this._resetExtraLabels(this._defaults, options);
		extendRemove(this._defaults, options || {});
	},

	/* Convert a date/time to UTC.
	   @param  tz     (number) the hour or minute offset from GMT, e.g. +9, -360
	   @param  year   (Date) the date/time in that timezone or
	                  (number) the year in that timezone
	   @param  month  (number, optional) the month (0 - 11) (omit if year is a Date)
	   @param  day    (number, optional) the day (omit if year is a Date)
	   @param  hours  (number, optional) the hour (omit if year is a Date)
	   @param  mins   (number, optional) the minute (omit if year is a Date)
	   @param  secs   (number, optional) the second (omit if year is a Date)
	   @param  ms     (number, optional) the millisecond (omit if year is a Date)
	   @return  (Date) the equivalent UTC date/time */
	UTCDate: function(tz, year, month, day, hours, mins, secs, ms) {
		if (typeof year == 'object' && year.constructor == Date) {
			ms = year.getMilliseconds();
			secs = year.getSeconds();
			mins = year.getMinutes();
			hours = year.getHours();
			day = year.getDate();
			month = year.getMonth();
			year = year.getFullYear();
		}
		var d = new Date();
		d.setUTCFullYear(year);
		d.setUTCDate(1);
		d.setUTCMonth(month || 0);
		d.setUTCDate(day || 1);
		d.setUTCHours(hours || 0);
		d.setUTCMinutes((mins || 0) - (Math.abs(tz) < 30 ? tz * 60 : tz));
		d.setUTCSeconds(secs || 0);
		d.setUTCMilliseconds(ms || 0);
		return d;
	},

	/* Convert a set of periods into seconds.
	   Averaged for months and years.
	   @param  periods  (number[7]) the periods per year/month/week/day/hour/minute/second
	   @return  (number) the corresponding number of seconds */
	periodsToSeconds: function(periods) {
		return periods[0] * 31557600 + periods[1] * 2629800 + periods[2] * 604800 +
			periods[3] * 86400 + periods[4] * 3600 + periods[5] * 60 + periods[6];
	},

	/* Retrieve one or more settings values.
	   @param  name  (string, optional) the name of the setting to retrieve
	                 or 'all' for all instance settings or omit for all default settings
	   @return  (any) the requested setting(s) */
	_settingsCountdown: function(target, name) {
		if (!name) {
			return $.countdown._defaults;
		}
		var inst = $.data(target, PROP_NAME);
		return (name == 'all' ? inst.options : inst.options[name]);
	},

	/* Attach the countdown widget to a div.
	   @param  target   (element) the containing division
	   @param  options  (object) the initial settings for the countdown */
	_attachCountdown: function(target, options) {
		var $target = $(target);
		if ($target.hasClass(this.markerClassName)) {
			return;
		}
		$target.addClass(this.markerClassName);
		var inst = {options: $.extend({}, options),
			_periods: [0, 0, 0, 0, 0, 0, 0]};
		$.data(target, PROP_NAME, inst);
		this._changeCountdown(target);
	},

	/* Add a target to the list of active ones.
	   @param  target  (element) the countdown target */
	_addTarget: function(target) {
		if (!this._hasTarget(target)) {
			this._timerTargets.push(target);
		}
	},

	/* See if a target is in the list of active ones.
	   @param  target  (element) the countdown target
	   @return  (boolean) true if present, false if not */
	_hasTarget: function(target) {
		return ($.inArray(target, this._timerTargets) > -1);
	},

	/* Remove a target from the list of active ones.
	   @param  target  (element) the countdown target */
	_removeTarget: function(target) {
		this._timerTargets = $.map(this._timerTargets,
			function(value) { return (value == target ? null : value); }); // delete entry
	},

	/* Update each active timer target. */
	_updateTargets: function() {
		for (var i = this._timerTargets.length - 1; i >= 0; i--) {
			this._updateCountdown(this._timerTargets[i]);
		}
	},

	/* Redisplay the countdown with an updated display.
	   @param  target  (jQuery) the containing division
	   @param  inst    (object) the current settings for this instance */
	_updateCountdown: function(target, inst) {
		var $target = $(target);
		inst = inst || $.data(target, PROP_NAME);
		if (!inst) {
			return;
		}
		$target.html(this._generateHTML(inst));
		$target[(this._get(inst, 'isRTL') ? 'add' : 'remove') + 'Class']('countdown_rtl');
		var onTick = this._get(inst, 'onTick');
		if (onTick) {
			var periods = inst._hold != 'lap' ? inst._periods :
				this._calculatePeriods(inst, inst._show, this._get(inst, 'significant'), new Date());
			var tickInterval = this._get(inst, 'tickInterval');
			if (tickInterval == 1 || this.periodsToSeconds(periods) % tickInterval == 0) {
				onTick.apply(target, [periods]);
			}
		}
		var expired = inst._hold != 'pause' &&
			(inst._since ? inst._now.getTime() < inst._since.getTime() :
			inst._now.getTime() >= inst._until.getTime());
		if (expired && !inst._expiring) {
			inst._expiring = true;
			if (this._hasTarget(target) || this._get(inst, 'alwaysExpire')) {
				this._removeTarget(target);
				var onExpiry = this._get(inst, 'onExpiry');
				if (onExpiry) {
					onExpiry.apply(target, []);
				}
				var expiryText = this._get(inst, 'expiryText');
				if (expiryText) {
					var layout = this._get(inst, 'layout');
					inst.options.layout = expiryText;
					this._updateCountdown(target, inst);
					inst.options.layout = layout;
				}
				var expiryUrl = this._get(inst, 'expiryUrl');
				if (expiryUrl) {
					window.location = expiryUrl;
				}
			}
			inst._expiring = false;
		}
		else if (inst._hold == 'pause') {
			this._removeTarget(target);
		}
		$.data(target, PROP_NAME, inst);
	},

	/* Reconfigure the settings for a countdown div.
	   @param  target   (element) the containing division
	   @param  options  (object) the new settings for the countdown or
	                    (string) an individual property name
	   @param  value    (any) the individual property value
	                    (omit if options is an object) */
	_changeCountdown: function(target, options, value) {
		options = options || {};
		if (typeof options == 'string') {
			var name = options;
			options = {};
			options[name] = value;
		}
		var inst = $.data(target, PROP_NAME);
		if (inst) {
			this._resetExtraLabels(inst.options, options);
			extendRemove(inst.options, options);
			this._adjustSettings(target, inst);
			$.data(target, PROP_NAME, inst);
			var now = new Date();
			if ((inst._since && inst._since < now) ||
					(inst._until && inst._until > now)) {
				this._addTarget(target);
			}
			this._updateCountdown(target, inst);
		}
	},

	/* Reset any extra labelsn and compactLabelsn entries if changing labels.
	   @param  base     (object) the options to be updated
	   @param  options  (object) the new option values */
	_resetExtraLabels: function(base, options) {
		var changingLabels = false;
		for (var n in options) {
			if (n != 'whichLabels' && n.match(/[Ll]abels/)) {
				changingLabels = true;
				break;
			}
		}
		if (changingLabels) {
			for (var n in base) { // Remove custom numbered labels
				if (n.match(/[Ll]abels[0-9]/)) {
					base[n] = null;
				}
			}
		}
	},
	
	/* Calculate interal settings for an instance.
	   @param  target  (element) the containing division
	   @param  inst    (object) the current settings for this instance */
	_adjustSettings: function(target, inst) {
		var now;
		var serverSync = this._get(inst, 'serverSync');
		var serverOffset = 0;
		var serverEntry = null;
		for (var i = 0; i < this._serverSyncs.length; i++) {
			if (this._serverSyncs[i][0] == serverSync) {
				serverEntry = this._serverSyncs[i][1];
				break;
			}
		}
		if (serverEntry != null) {
			serverOffset = (serverSync ? serverEntry : 0);
			now = new Date();
		}
		else {
			var serverResult = (serverSync ? serverSync.apply(target, []) : null);
			now = new Date();
			serverOffset = (serverResult ? now.getTime() - serverResult.getTime() : 0);
			this._serverSyncs.push([serverSync, serverOffset]);
		}
		var timezone = this._get(inst, 'timezone');
		timezone = (timezone == null ? -now.getTimezoneOffset() : timezone);
		inst._since = this._get(inst, 'since');
		if (inst._since != null) {
			inst._since = this.UTCDate(timezone, this._determineTime(inst._since, null));
			if (inst._since && serverOffset) {
				inst._since.setMilliseconds(inst._since.getMilliseconds() + serverOffset);
			}
		}
		inst._until = this.UTCDate(timezone, this._determineTime(this._get(inst, 'until'), now));
		if (serverOffset) {
			inst._until.setMilliseconds(inst._until.getMilliseconds() + serverOffset);
		}
		inst._show = this._determineShow(inst);
	},

	/* Remove the countdown widget from a div.
	   @param  target  (element) the containing division */
	_destroyCountdown: function(target) {
		var $target = $(target);
		if (!$target.hasClass(this.markerClassName)) {
			return;
		}
		this._removeTarget(target);
		$target.removeClass(this.markerClassName).empty();
		$.removeData(target, PROP_NAME);
	},

	/* Pause a countdown widget at the current time.
	   Stop it running but remember and display the current time.
	   @param  target  (element) the containing division */
	_pauseCountdown: function(target) {
		this._hold(target, 'pause');
	},

	/* Pause a countdown widget at the current time.
	   Stop the display but keep the countdown running.
	   @param  target  (element) the containing division */
	_lapCountdown: function(target) {
		this._hold(target, 'lap');
	},

	/* Resume a paused countdown widget.
	   @param  target  (element) the containing division */
	_resumeCountdown: function(target) {
		this._hold(target, null);
	},

	/* Pause or resume a countdown widget.
	   @param  target  (element) the containing division
	   @param  hold    (string) the new hold setting */
	_hold: function(target, hold) {
		var inst = $.data(target, PROP_NAME);
		if (inst) {
			if (inst._hold == 'pause' && !hold) {
				inst._periods = inst._savePeriods;
				var sign = (inst._since ? '-' : '+');
				inst[inst._since ? '_since' : '_until'] =
					this._determineTime(sign + inst._periods[0] + 'y' +
						sign + inst._periods[1] + 'o' + sign + inst._periods[2] + 'w' +
						sign + inst._periods[3] + 'd' + sign + inst._periods[4] + 'h' + 
						sign + inst._periods[5] + 'm' + sign + inst._periods[6] + 's');
				this._addTarget(target);
			}
			inst._hold = hold;
			inst._savePeriods = (hold == 'pause' ? inst._periods : null);
			$.data(target, PROP_NAME, inst);
			this._updateCountdown(target, inst);
		}
	},

	/* Return the current time periods.
	   @param  target  (element) the containing division
	   @return  (number[7]) the current periods for the countdown */
	_getTimesCountdown: function(target) {
		var inst = $.data(target, PROP_NAME);
		return (!inst ? null : (!inst._hold ? inst._periods :
			this._calculatePeriods(inst, inst._show, this._get(inst, 'significant'), new Date())));
	},

	/* Get a setting value, defaulting if necessary.
	   @param  inst  (object) the current settings for this instance
	   @param  name  (string) the name of the required setting
	   @return  (any) the setting's value or a default if not overridden */
	_get: function(inst, name) {
		return (inst.options[name] != null ?
			inst.options[name] : $.countdown._defaults[name]);
	},

	/* A time may be specified as an exact value or a relative one.
	   @param  setting      (string or number or Date) - the date/time value
	                        as a relative or absolute value
	   @param  defaultTime  (Date) the date/time to use if no other is supplied
	   @return  (Date) the corresponding date/time */
	_determineTime: function(setting, defaultTime) {
		var offsetNumeric = function(offset) { // e.g. +300, -2
			var time = new Date();
			time.setTime(time.getTime() + offset * 1000);
			return time;
		};
		var offsetString = function(offset) { // e.g. '+2d', '-4w', '+3h +30m'
			offset = offset.toLowerCase();
			var time = new Date();
			var year = time.getFullYear();
			var month = time.getMonth();
			var day = time.getDate();
			var hour = time.getHours();
			var minute = time.getMinutes();
			var second = time.getSeconds();
			var pattern = /([+-]?[0-9]+)\s*(s|m|h|d|w|o|y)?/g;
			var matches = pattern.exec(offset);
			while (matches) {
				switch (matches[2] || 's') {
					case 's': second += parseInt(matches[1], 10); break;
					case 'm': minute += parseInt(matches[1], 10); break;
					case 'h': hour += parseInt(matches[1], 10); break;
					case 'd': day += parseInt(matches[1], 10); break;
					case 'w': day += parseInt(matches[1], 10) * 7; break;
					case 'o':
						month += parseInt(matches[1], 10); 
						day = Math.min(day, $.countdown._getDaysInMonth(year, month));
						break;
					case 'y':
						year += parseInt(matches[1], 10);
						day = Math.min(day, $.countdown._getDaysInMonth(year, month));
						break;
				}
				matches = pattern.exec(offset);
			}
			return new Date(year, month, day, hour, minute, second, 0);
		};
		var time = (setting == null ? defaultTime :
			(typeof setting == 'string' ? offsetString(setting) :
			(typeof setting == 'number' ? offsetNumeric(setting) : setting)));
		if (time) time.setMilliseconds(0);
		return time;
	},

	/* Determine the number of days in a month.
	   @param  year   (number) the year
	   @param  month  (number) the month
	   @return  (number) the days in that month */
	_getDaysInMonth: function(year, month) {
		return 32 - new Date(year, month, 32).getDate();
	},

	/* Determine which set of labels should be used for an amount.
	   @param  num  (number) the amount to be displayed
	   @return  (number) the set of labels to be used for this amount */
	_normalLabels: function(num) {
		return num;
	},

	/* Generate the HTML to display the countdown widget.
	   @param  inst  (object) the current settings for this instance
	   @return  (string) the new HTML for the countdown display */
	_generateHTML: function(inst) {
		// Determine what to show
		var significant = this._get(inst, 'significant');
		inst._periods = (inst._hold ? inst._periods :
			this._calculatePeriods(inst, inst._show, significant, new Date()));
		// Show all 'asNeeded' after first non-zero value
		var shownNonZero = false;
		var showCount = 0;
		var sigCount = significant;
		var show = $.extend({}, inst._show);
		for (var period = Y; period <= S; period++) {
			shownNonZero |= (inst._show[period] == '?' && inst._periods[period] > 0);
			show[period] = (inst._show[period] == '?' && !shownNonZero ? null : inst._show[period]);
			showCount += (show[period] ? 1 : 0);
			sigCount -= (inst._periods[period] > 0 ? 1 : 0);
		}
		var showSignificant = [false, false, false, false, false, false, false];
		for (var period = S; period >= Y; period--) { // Determine significant periods
			if (inst._show[period]) {
				if (inst._periods[period]) {
					showSignificant[period] = true;
				}
				else {
					showSignificant[period] = sigCount > 0;
					sigCount--;
				}
			}
		}
		var compact = this._get(inst, 'compact');
		var layout = this._get(inst, 'layout');
		var labels = (compact ? this._get(inst, 'compactLabels') : this._get(inst, 'labels'));
		var whichLabels = this._get(inst, 'whichLabels') || this._normalLabels;
		var timeSeparator = this._get(inst, 'timeSeparator');
		var description = this._get(inst, 'description') || '';
		var showCompact = function(period) {
			var labelsNum = $.countdown._get(inst,
				'compactLabels' + whichLabels(inst._periods[period]));
			return (show[period] ? inst._periods[period] +
				(labelsNum ? labelsNum[period] : labels[period]) + ' ' : '');
		};
		var showFull = function(period) {
			var labelsNum = $.countdown._get(inst, 'labels' + whichLabels(inst._periods[period]));
			return ((!significant && show[period]) || (significant && showSignificant[period]) ?
				'<span class="countdown_section"><span class="countdown_amount">' +
				inst._periods[period] + '</span><br/>' +
				(labelsNum ? labelsNum[period] : labels[period]) + '</span>' : '');
		};
		return (layout ? this._buildLayout(inst, show, layout, compact, significant, showSignificant) :
			((compact ? // Compact version
			'<span class="countdown_row countdown_amount' +
			(inst._hold ? ' countdown_holding' : '') + '">' + 
			showCompact(Y) + showCompact(O) + showCompact(W) + showCompact(D) + 
			(show[H] ? this._minDigits(inst._periods[H], 2) : '') +
			(show[M] ? (show[H] ? timeSeparator : '') +
			this._minDigits(inst._periods[M], 2) : '') +
			(show[S] ? (show[H] || show[M] ? timeSeparator : '') +
			this._minDigits(inst._periods[S], 2) : '') :
			// Full version
			'<span class="countdown_row countdown_show' + (significant || showCount) +
			(inst._hold ? ' countdown_holding' : '') + '">' +
			showFull(Y) + showFull(O) + showFull(W) + showFull(D) +
			showFull(H) + showFull(M) + showFull(S)) + '</span>' +
			(description ? '<span class="countdown_row countdown_descr">' + description + '</span>' : '')));
	},

	/* Construct a custom layout.
	   @param  inst             (object) the current settings for this instance
	   @param  show             (string[7]) flags indicating which periods are requested
	   @param  layout           (string) the customised layout
	   @param  compact          (boolean) true if using compact labels
	   @param  significant      (number) the number of periods with values to show, zero for all
	   @param  showSignificant  (boolean[7]) other periods to show for significance
	   @return  (string) the custom HTML */
	_buildLayout: function(inst, show, layout, compact, significant, showSignificant) {
		var labels = this._get(inst, (compact ? 'compactLabels' : 'labels'));
		var whichLabels = this._get(inst, 'whichLabels') || this._normalLabels;
		var labelFor = function(index) {
			return ($.countdown._get(inst,
				(compact ? 'compactLabels' : 'labels') + whichLabels(inst._periods[index])) ||
				labels)[index];
		};
		var digit = function(value, position) {
			return Math.floor(value / position) % 10;
		};
		var subs = {desc: this._get(inst, 'description'), sep: this._get(inst, 'timeSeparator'),
			yl: labelFor(Y), yn: inst._periods[Y], ynn: this._minDigits(inst._periods[Y], 2),
			ynnn: this._minDigits(inst._periods[Y], 3), y1: digit(inst._periods[Y], 1),
			y10: digit(inst._periods[Y], 10), y100: digit(inst._periods[Y], 100),
			y1000: digit(inst._periods[Y], 1000),
			ol: labelFor(O), on: inst._periods[O], onn: this._minDigits(inst._periods[O], 2),
			onnn: this._minDigits(inst._periods[O], 3), o1: digit(inst._periods[O], 1),
			o10: digit(inst._periods[O], 10), o100: digit(inst._periods[O], 100),
			o1000: digit(inst._periods[O], 1000),
			wl: labelFor(W), wn: inst._periods[W], wnn: this._minDigits(inst._periods[W], 2),
			wnnn: this._minDigits(inst._periods[W], 3), w1: digit(inst._periods[W], 1),
			w10: digit(inst._periods[W], 10), w100: digit(inst._periods[W], 100),
			w1000: digit(inst._periods[W], 1000),
			dl: labelFor(D), dn: inst._periods[D], dnn: this._minDigits(inst._periods[D], 2),
			dnnn: this._minDigits(inst._periods[D], 3), d1: digit(inst._periods[D], 1),
			d10: digit(inst._periods[D], 10), d100: digit(inst._periods[D], 100),
			d1000: digit(inst._periods[D], 1000),
			hl: labelFor(H), hn: inst._periods[H], hnn: this._minDigits(inst._periods[H], 2),
			hnnn: this._minDigits(inst._periods[H], 3), h1: digit(inst._periods[H], 1),
			h10: digit(inst._periods[H], 10), h100: digit(inst._periods[H], 100),
			h1000: digit(inst._periods[H], 1000),
			ml: labelFor(M), mn: inst._periods[M], mnn: this._minDigits(inst._periods[M], 2),
			mnnn: this._minDigits(inst._periods[M], 3), m1: digit(inst._periods[M], 1),
			m10: digit(inst._periods[M], 10), m100: digit(inst._periods[M], 100),
			m1000: digit(inst._periods[M], 1000),
			sl: labelFor(S), sn: inst._periods[S], snn: this._minDigits(inst._periods[S], 2),
			snnn: this._minDigits(inst._periods[S], 3), s1: digit(inst._periods[S], 1),
			s10: digit(inst._periods[S], 10), s100: digit(inst._periods[S], 100),
			s1000: digit(inst._periods[S], 1000)};
		var html = layout;
		// Replace period containers: {p<}...{p>}
		for (var i = Y; i <= S; i++) {
			var period = 'yowdhms'.charAt(i);
			var re = new RegExp('\\{' + period + '<\\}(.*)\\{' + period + '>\\}', 'g');
			html = html.replace(re, ((!significant && show[i]) ||
				(significant && showSignificant[i]) ? '$1' : ''));
		}
		// Replace period values: {pn}
		$.each(subs, function(n, v) {
			var re = new RegExp('\\{' + n + '\\}', 'g');
			html = html.replace(re, v);
		});
		return html;
	},

	/* Ensure a numeric value has at least n digits for display.
	   @param  value  (number) the value to display
	   @param  len    (number) the minimum length
	   @return  (string) the display text */
	_minDigits: function(value, len) {
		value = '' + value;
		if (value.length >= len) {
			return value;
		}
		value = '0000000000' + value;
		return value.substr(value.length - len);
	},

	/* Translate the format into flags for each period.
	   @param  inst  (object) the current settings for this instance
	   @return  (string[7]) flags indicating which periods are requested (?) or
	            required (!) by year, month, week, day, hour, minute, second */
	_determineShow: function(inst) {
		var format = this._get(inst, 'format');
		var show = [];
		show[Y] = (format.match('y') ? '?' : (format.match('Y') ? '!' : null));
		show[O] = (format.match('o') ? '?' : (format.match('O') ? '!' : null));
		show[W] = (format.match('w') ? '?' : (format.match('W') ? '!' : null));
		show[D] = (format.match('d') ? '?' : (format.match('D') ? '!' : null));
		show[H] = (format.match('h') ? '?' : (format.match('H') ? '!' : null));
		show[M] = (format.match('m') ? '?' : (format.match('M') ? '!' : null));
		show[S] = (format.match('s') ? '?' : (format.match('S') ? '!' : null));
		return show;
	},
	
	/* Calculate the requested periods between now and the target time.
	   @param  inst         (object) the current settings for this instance
	   @param  show         (string[7]) flags indicating which periods are requested/required
	   @param  significant  (number) the number of periods with values to show, zero for all
	   @param  now          (Date) the current date and time
	   @return  (number[7]) the current time periods (always positive)
	            by year, month, week, day, hour, minute, second */
	_calculatePeriods: function(inst, show, significant, now) {
		// Find endpoints
		inst._now = now;
		inst._now.setMilliseconds(0);
		var until = new Date(inst._now.getTime());
		if (inst._since) {
			if (now.getTime() < inst._since.getTime()) {
				inst._now = now = until;
			}
			else {
				now = inst._since;
			}
		}
		else {
			until.setTime(inst._until.getTime());
			if (now.getTime() > inst._until.getTime()) {
				inst._now = now = until;
			}
		}
		// Calculate differences by period
		var periods = [0, 0, 0, 0, 0, 0, 0];
		if (show[Y] || show[O]) {
			// Treat end of months as the same
			var lastNow = $.countdown._getDaysInMonth(now.getFullYear(), now.getMonth());
			var lastUntil = $.countdown._getDaysInMonth(until.getFullYear(), until.getMonth());
			var sameDay = (until.getDate() == now.getDate() ||
				(until.getDate() >= Math.min(lastNow, lastUntil) &&
				now.getDate() >= Math.min(lastNow, lastUntil)));
			var getSecs = function(date) {
				return (date.getHours() * 60 + date.getMinutes()) * 60 + date.getSeconds();
			};
			var months = Math.max(0,
				(until.getFullYear() - now.getFullYear()) * 12 + until.getMonth() - now.getMonth() +
				((until.getDate() < now.getDate() && !sameDay) ||
				(sameDay && getSecs(until) < getSecs(now)) ? -1 : 0));
			periods[Y] = (show[Y] ? Math.floor(months / 12) : 0);
			periods[O] = (show[O] ? months - periods[Y] * 12 : 0);
			// Adjust for months difference and end of month if necessary
			now = new Date(now.getTime());
			var wasLastDay = (now.getDate() == lastNow);
			var lastDay = $.countdown._getDaysInMonth(now.getFullYear() + periods[Y],
				now.getMonth() + periods[O]);
			if (now.getDate() > lastDay) {
				now.setDate(lastDay);
			}
			now.setFullYear(now.getFullYear() + periods[Y]);
			now.setMonth(now.getMonth() + periods[O]);
			if (wasLastDay) {
				now.setDate(lastDay);
			}
		}
		var diff = Math.floor((until.getTime() - now.getTime()) / 1000);
		var extractPeriod = function(period, numSecs) {
			periods[period] = (show[period] ? Math.floor(diff / numSecs) : 0);
			diff -= periods[period] * numSecs;
		};
		extractPeriod(W, 604800);
		extractPeriod(D, 86400);
		extractPeriod(H, 3600);
		extractPeriod(M, 60);
		extractPeriod(S, 1);
		if (diff > 0 && !inst._since) { // Round up if left overs
			var multiplier = [1, 12, 4.3482, 7, 24, 60, 60];
			var lastShown = S;
			var max = 1;
			for (var period = S; period >= Y; period--) {
				if (show[period]) {
					if (periods[lastShown] >= max) {
						periods[lastShown] = 0;
						diff = 1;
					}
					if (diff > 0) {
						periods[period]++;
						diff = 0;
						lastShown = period;
						max = 1;
					}
				}
				max *= multiplier[period];
			}
		}
		if (significant) { // Zero out insignificant periods
			for (var period = Y; period <= S; period++) {
				if (significant && periods[period]) {
					significant--;
				}
				else if (!significant) {
					periods[period] = 0;
				}
			}
		}
		return periods;
	}
});

/* jQuery extend now ignores nulls!
   @param  target  (object) the object to update
   @param  props   (object) the new settings
   @return  (object) the updated object */
function extendRemove(target, props) {
	$.extend(target, props);
	for (var name in props) {
		if (props[name] == null) {
			target[name] = null;
		}
	}
	return target;
}

/* Process the countdown functionality for a jQuery selection.
   @param  command  (string) the command to run (optional, default 'attach')
   @param  options  (object) the new settings to use for these countdown instances
   @return  (jQuery) for chaining further calls */
$.fn.countdown = function(options) {
	var otherArgs = Array.prototype.slice.call(arguments, 1);
	if (options == 'getTimes' || options == 'settings') {
		return $.countdown['_' + options + 'Countdown'].
			apply($.countdown, [this[0]].concat(otherArgs));
	}
	return this.each(function() {
		if (typeof options == 'string') {
			$.countdown['_' + options + 'Countdown'].apply($.countdown, [this].concat(otherArgs));
		}
		else {
			$.countdown._attachCountdown(this, options);
		}
	});
};

/* Initialise the countdown functionality. */
$.countdown = new Countdown(); // singleton instance

})(jQuery);
ï»¿/* http://keith-wood.name/countdown.html
   French initialisation for the jQuery countdown extension
   Written by Keith Wood (kbwood{at}iinet.com.au) Jan 2008. */
(function($) {
	$.countdown.regional['fr'] = {
		labels: ['AnnÃ©es', 'Mois', 'Semaines', 'Jours', 'Heures', 'Minutes', 'Secondes'],
		labels1: ['AnnÃ©e', 'Mois', 'Semaine', 'Jour', 'Heure', 'Minute', 'Seconde'],
		compactLabels: ['a', 'm', 's', 'j', 'h', 'm', 's'],
		whichLabels: null,
		timeSeparator: ':', isRTL: false};
	$.countdown.setDefaults($.countdown.regional['fr']);
})(jQuery);

