﻿/*! Copyright (c) 2008 Brandon Aaron (http://brandonaaron.net)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * Version: 1.0.3
 * Requires jQuery 1.1.3+
 * Docs: http://docs.jquery.com/Plugins/livequery
 */

(function($) {
	
$.extend($.fn, {
	livequery: function(type, fn, fn2) {
		var self = this, q;
		
		// Handle different call patterns
		if ($.isFunction(type))
			fn2 = fn, fn = type, type = undefined;
			
		// See if Live Query already exists
		$.each( $.livequery.queries, function(i, query) {
			if ( self.selector == query.selector && self.context == query.context &&
				type == query.type && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid) )
					// Found the query, exit the each loop
					return (q = query) && false;
		});
		
		// Create new Live Query if it wasn't found
		q = q || new $.livequery(this.selector, this.context, type, fn, fn2);
		
		// Make sure it is running
		q.stopped = false;
		
		// Run it immediately for the first time
		q.run();
		
		// Contnue the chain
		return this;
	},
	
	expire: function(type, fn, fn2) {
		var self = this;
		
		// Handle different call patterns
		if ($.isFunction(type))
			fn2 = fn, fn = type, type = undefined;
			
		// Find the Live Query based on arguments and stop it
		$.each( $.livequery.queries, function(i, query) {
			if ( self.selector == query.selector && self.context == query.context && 
				(!type || type == query.type) && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid) && !this.stopped )
					$.livequery.stop(query.id);
		});
		
		// Continue the chain
		return this;
	}
});

$.livequery = function(selector, context, type, fn, fn2) {
	this.selector = selector;
	this.context  = context || document;
	this.type     = type;
	this.fn       = fn;
	this.fn2      = fn2;
	this.elements = [];
	this.stopped  = false;
	
	// The id is the index of the Live Query in $.livequery.queries
	this.id = $.livequery.queries.push(this)-1;
	
	// Mark the functions for matching later on
	fn.$lqguid = fn.$lqguid || $.livequery.guid++;
	if (fn2) fn2.$lqguid = fn2.$lqguid || $.livequery.guid++;
	
	// Return the Live Query
	return this;
};

$.livequery.prototype = {
	stop: function() {
		var query = this;
		
		if ( this.type )
			// Unbind all bound events
			this.elements.unbind(this.type, this.fn);
		else if (this.fn2)
			// Call the second function for all matched elements
			this.elements.each(function(i, el) {
				query.fn2.apply(el);
			});
			
		// Clear out matched elements
		this.elements = [];
		
		// Stop the Live Query from running until restarted
		this.stopped = true;
	},
	
	run: function() {
		// Short-circuit if stopped
		if ( this.stopped ) return;
		var query = this;
		
		var oEls = this.elements,
			els  = $(this.selector, this.context),
			nEls = els.not(oEls);
		
		// Set elements to the latest set of matched elements
		this.elements = els;
		
		if (this.type) {
			// Bind events to newly matched elements
			nEls.bind(this.type, this.fn);
			
			// Unbind events to elements no longer matched
			if (oEls.length > 0)
				$.each(oEls, function(i, el) {
					if ( $.inArray(el, els) < 0 )
						$.event.remove(el, query.type, query.fn);
				});
		}
		else {
			// Call the first function for newly matched elements
			nEls.each(function() {
				query.fn.apply(this);
			});
			
			// Call the second function for elements no longer matched
			if ( this.fn2 && oEls.length > 0 )
				$.each(oEls, function(i, el) {
					if ( $.inArray(el, els) < 0 )
						query.fn2.apply(el);
				});
		}
	}
};

$.extend($.livequery, {
	guid: 0,
	queries: [],
	queue: [],
	running: false,
	timeout: null,
	
	checkQueue: function() {
		if ( $.livequery.running && $.livequery.queue.length ) {
			var length = $.livequery.queue.length;
			// Run each Live Query currently in the queue
			while ( length-- )
				$.livequery.queries[ $.livequery.queue.shift() ].run();
		}
	},
	
	pause: function() {
		// Don't run anymore Live Queries until restarted
		$.livequery.running = false;
	},
	
	play: function() {
		// Restart Live Queries
		$.livequery.running = true;
		// Request a run of the Live Queries
		$.livequery.run();
	},
	
	registerPlugin: function() {
		$.each( arguments, function(i,n) {
			// Short-circuit if the method doesn't exist
			if (!$.fn[n]) return;
			
			// Save a reference to the original method
			var old = $.fn[n];
			
			// Create a new method
			$.fn[n] = function() {
				// Call the original method
				var r = old.apply(this, arguments);
				
				// Request a run of the Live Queries
				$.livequery.run();
				
				// Return the original methods result
				return r;
			}
		});
	},
	
	run: function(id) {
		if (id != undefined) {
			// Put the particular Live Query in the queue if it doesn't already exist
			if ( $.inArray(id, $.livequery.queue) < 0 )
				$.livequery.queue.push( id );
		}
		else
			// Put each Live Query in the queue if it doesn't already exist
			$.each( $.livequery.queries, function(id) {
				if ( $.inArray(id, $.livequery.queue) < 0 )
					$.livequery.queue.push( id );
			});
		
		// Clear timeout if it already exists
		if ($.livequery.timeout) clearTimeout($.livequery.timeout);
		// Create a timeout to check the queue and actually run the Live Queries
		$.livequery.timeout = setTimeout($.livequery.checkQueue, 20);
	},
	
	stop: function(id) {
		if (id != undefined)
			// Stop are particular Live Query
			$.livequery.queries[ id ].stop();
		else
			// Stop all Live Queries
			$.each( $.livequery.queries, function(id) {
				$.livequery.queries[ id ].stop();
			});
	}
});

// Register core DOM manipulation methods
$.livequery.registerPlugin('append', 'prepend', 'after', 'before', 'wrap', 'attr', 'removeAttr', 'addClass', 'removeClass', 'toggleClass', 'empty', 'remove');

// Run Live Queries when the Document is ready
$(function() { $.livequery.play(); });


// Save a reference to the original init method
var init = $.prototype.init;

// Create a new init method that exposes two new properties: selector and context
$.prototype.init = function(a,c) {
	// Call the original init and save the result
	var r = init.apply(this, arguments);
	
	// Copy over properties if they exist already
	if (a && a.selector)
		r.context = a.context, r.selector = a.selector;
		
	// Set properties
	if ( typeof a == 'string' )
		r.context = c || document, r.selector = a;
	
	// Return the result
	return r;
};

// Give the init function the jQuery prototype for later instantiation (needed after Rev 4091)
$.prototype.init.prototype = $.prototype;
	
})(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
 */;(function($){var helper={},current,title,tID,IE=$.browser.msie&&/MSIE\s(5\.5|6\.)/.test(navigator.userAgent),track=false;$.tooltip={blocked:false,defaults:{delay:200,fade:false,showURL:true,extraClass:"",top:15,left:15,id:"tooltip"},block:function(){$.tooltip.blocked=!$.tooltip.blocked;}};$.fn.extend({tooltip:function(settings){settings=$.extend({},$.tooltip.defaults,settings);createHelper(settings);return this.each(function(){$.data(this,"tooltip",settings);this.tOpacity=helper.parent.css("opacity");this.tooltipText=this.title;$(this).removeAttr("title");this.alt="";}).mouseover(save).mouseout(hide).click(hide);},fixPNG:IE?function(){return this.each(function(){var image=$(this).css('backgroundImage');if(image.match(/^url\(["']?(.*\.png)["']?\)$/i)){image=RegExp.$1;$(this).css({'backgroundImage':'none','filter':"progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='"+image+"')"}).each(function(){var position=$(this).css('position');if(position!='absolute'&&position!='relative')$(this).css('position','relative');});}});}:function(){return this;},unfixPNG:IE?function(){return this.each(function(){$(this).css({'filter':'',backgroundImage:''});});}:function(){return this;},hideWhenEmpty:function(){return this.each(function(){$(this)[$(this).html()?"show":"hide"]();});},url:function(){return this.attr('href')||this.attr('src');}});function createHelper(settings){if(helper.parent)return;helper.parent=$('<div id="'+settings.id+'"><h3></h3><div class="body"></div><div class="url"></div></div>').appendTo(document.body).hide();if($.fn.bgiframe)helper.parent.bgiframe();helper.title=$('h3',helper.parent);helper.body=$('div.body',helper.parent);helper.url=$('div.url',helper.parent);}function settings(element){return $.data(element,"tooltip");}function handle(event){if(settings(this).delay)tID=setTimeout(show,settings(this).delay);else
show();track=!!settings(this).track;$(document.body).bind('mousemove',update);update(event);}function save(){if($.tooltip.blocked||this==current||(!this.tooltipText&&!settings(this).bodyHandler))return;current=this;title=this.tooltipText;if(settings(this).bodyHandler){helper.title.hide();var bodyContent=settings(this).bodyHandler.call(this);if(bodyContent.nodeType||bodyContent.jquery){helper.body.empty().append(bodyContent)}else{helper.body.html(bodyContent);}helper.body.show();}else if(settings(this).showBody){var parts=title.split(settings(this).showBody);helper.title.html(parts.shift()).show();helper.body.empty();for(var i=0,part;(part=parts[i]);i++){if(i>0)helper.body.append("<br/>");helper.body.append(part);}helper.body.hideWhenEmpty();}else{helper.title.html(title).show();helper.body.hide();}if(settings(this).showURL&&$(this).url())helper.url.html($(this).url().replace('http://','')).show();else
helper.url.hide();helper.parent.addClass(settings(this).extraClass);if(settings(this).fixPNG)helper.parent.fixPNG();handle.apply(this,arguments);}function show(){tID=null;if((!IE||!$.fn.bgiframe)&&settings(current).fade){if(helper.parent.is(":animated"))helper.parent.stop().show().fadeTo(settings(current).fade,current.tOpacity);else
helper.parent.is(':visible')?helper.parent.fadeTo(settings(current).fade,current.tOpacity):helper.parent.fadeIn(settings(current).fade);}else{helper.parent.show();}update();}function update(event){if($.tooltip.blocked)return;if(event&&event.target.tagName=="OPTION"){return;}if(!track&&helper.parent.is(":visible")){$(document.body).unbind('mousemove',update)}if(current==null){$(document.body).unbind('mousemove',update);return;}helper.parent.removeClass("viewport-right").removeClass("viewport-bottom");var left=helper.parent[0].offsetLeft;var top=helper.parent[0].offsetTop;if(event){left=event.pageX+settings(current).left;top=event.pageY+settings(current).top;var right='auto';if(settings(current).positionLeft){right=$(window).width()-left;left='auto';}helper.parent.css({left:left,right:right,top:top});}var v=viewport(),h=helper.parent[0];if(v.x+v.cx<h.offsetLeft+h.offsetWidth){left-=h.offsetWidth+20+settings(current).left;helper.parent.css({left:left+'px'}).addClass("viewport-right");}if(v.y+v.cy<h.offsetTop+h.offsetHeight){top-=h.offsetHeight+20+settings(current).top;helper.parent.css({top:top+'px'}).addClass("viewport-bottom");}}function viewport(){return{x:$(window).scrollLeft(),y:$(window).scrollTop(),cx:$(window).width(),cy:$(window).height()};}function hide(event){if($.tooltip.blocked)return;if(tID)clearTimeout(tID);current=null;var tsettings=settings(this);function complete(){helper.parent.removeClass(tsettings.extraClass).hide().css("opacity","");}if((!IE||!$.fn.bgiframe)&&tsettings.fade){if(helper.parent.is(':animated'))helper.parent.stop().fadeTo(tsettings.fade,0,complete);else
helper.parent.stop().fadeOut(tsettings.fade,complete);}else
complete();if(settings(this).fixPNG)helper.parent.unfixPNG();}})(jQuery);
/*
* jQuery validation plug-in 1.5.5
*
* http://bassistance.de/jquery-plugins/jquery-plugin-validation/
* http://docs.jquery.com/Plugins/Validation
*
* Copyright (c) 2006 - 2008 Jörn Zaefferer
*
* $Id: jquery.validate.js 6403 2009-06-17 14:27: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
*/

(function($) {

    $.extend($.fn, {
        // http://docs.jquery.com/Plugins/Validation/validate
        validate: function(options) {

            // if nothing is selected, return nothing; can't chain anyway
            if (!this.length) {
                options && options.debug && window.console && console.warn("nothing selected, can't validate, returning nothing");
                return;
            }

            // check if a validator for this form was already created
            var validator = $.data(this[0], 'validator');
            if (validator) {
                return validator;
            }

            validator = new $.validator(options, this[0]);
            $.data(this[0], 'validator', validator);

            if (validator.settings.onsubmit) {

                // allow suppresing validation by adding a cancel class to the submit button
                this.find("input, button").filter(".cancel").click(function() {
                    validator.cancelSubmit = true;
                });

                // when a submitHandler is used, capture the submitting button
                if (validator.settings.submitHandler) {
                    this.find("input, button").filter(":submit").click(function() {
                        validator.submitButton = this;
                    });
                }

                // validate the form on submit
                this.submit(function(event) {
                    if (validator.settings.debug)
                    // prevent form submit to be able to see console output
                        event.preventDefault();

                    function handle() {
                        if (validator.settings.submitHandler) {
                            if (validator.submitButton) {
                                // insert a hidden input as a replacement for the missing submit button
                                var hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm);
                            }
                            validator.settings.submitHandler.call(validator, validator.currentForm);
                            if (validator.submitButton) {
                                // and clean up afterwards; thanks to no-block-scope, hidden can be referenced
                                hidden.remove();
                            }
                            return false;
                        }
                        return true;
                    }

                    // prevent submit for invalid forms or custom submit handlers
                    if (validator.cancelSubmit) {
                        validator.cancelSubmit = false;
                        return handle();
                    }
                    if (validator.form()) {
                        if (validator.pendingRequest) {
                            validator.formSubmitted = true;
                            return false;
                        }
                        return handle();
                    } else {
                        validator.focusInvalid();
                        return false;
                    }
                });
            }

            return validator;
        },
        // http://docs.jquery.com/Plugins/Validation/valid
        valid: function() {
            if ($(this[0]).is('form')) {
                return this.validate().form();
            } else {
                var valid = true;
                var validator = $(this[0].form).validate();
                this.each(function() {
                    valid &= validator.element(this);
                });
                return valid;
            }
        },
        // attributes: space seperated list of attributes to retrieve and remove
        removeAttrs: function(attributes) {
            var result = {},
			$element = this;
            $.each(attributes.split(/\s/), function(index, value) {
                result[value] = $element.attr(value);
                $element.removeAttr(value);
            });
            return result;
        },
        // http://docs.jquery.com/Plugins/Validation/rules
        rules: function(command, argument) {
            var element = this[0];

            if (command) {
                var settings = $.data(element.form, 'validator').settings;
                var staticRules = settings.rules;
                var existingRules = $.validator.staticRules(element);
                switch (command) {
                    case "add":
                        $.extend(existingRules, $.validator.normalizeRule(argument));
                        staticRules[element.name] = existingRules;
                        if (argument.messages)
                            settings.messages[element.name] = $.extend(settings.messages[element.name], argument.messages);
                        break;
                    case "remove":
                        if (!argument) {
                            delete staticRules[element.name];
                            return existingRules;
                        }
                        var filtered = {};
                        $.each(argument.split(/\s/), function(index, method) {
                            filtered[method] = existingRules[method];
                            delete existingRules[method];
                        });
                        return filtered;
                }
            }

            var data = $.validator.normalizeRules(
		$.extend(
			{},
			$.validator.metadataRules(element),
			$.validator.classRules(element),
			$.validator.attributeRules(element),
			$.validator.staticRules(element)
		), element);

            // make sure required is at front
            if (data.required) {
                var param = data.required;
                delete data.required;
                data = $.extend({ required: param }, data);
            }

            return data;
        }
    });

    // Custom selectors
    $.extend($.expr[":"], {
        // http://docs.jquery.com/Plugins/Validation/blank
        blank: function(a) { return !$.trim(a.value); },
        // http://docs.jquery.com/Plugins/Validation/filled
        filled: function(a) { return !!$.trim(a.value); },
        // http://docs.jquery.com/Plugins/Validation/unchecked
        unchecked: function(a) { return !a.checked; }
    });

    // constructor for validator
    $.validator = function(options, form) {
        this.settings = $.extend({}, $.validator.defaults, options);
        this.currentForm = form;
        this.init();
    };

    $.validator.format = function(source, params) {
        if (arguments.length == 1)
            return function() {
                var args = $.makeArray(arguments);
                args.unshift(source);
                return $.validator.format.apply(this, args);
            };
        if (arguments.length > 2 && params.constructor != Array) {
            params = $.makeArray(arguments).slice(1);
        }
        if (params.constructor != Array) {
            params = [params];
        }
        $.each(params, function(i, n) {
            source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n);
        });
        return source;
    };

    $.extend($.validator, {

        defaults: {
            messages: {},
            groups: {},
            rules: {},
            errorClass: "error",
            validClass: "valid",
            errorElement: "label",
            focusInvalid: true,
            errorContainer: $([]),
            errorLabelContainer: $([]),
            onsubmit: true,
            ignore: [],
            ignoreTitle: false,
            onfocusin: function(element) {
                this.lastActive = element;

                // hide error label and remove error class on focus if enabled
                if (this.settings.focusCleanup && !this.blockFocusCleanup) {
                    this.settings.unhighlight && this.settings.unhighlight.call(this, element, this.settings.errorClass, this.settings.validClass);
                    this.errorsFor(element).hide();
                }
            },
            onfocusout: function(element) {
                if (!this.checkable(element) && (element.name in this.submitted || !this.optional(element))) {
                    this.element(element);
                }
            },
            onkeyup: function(element) {
                if (element.name in this.submitted || element == this.lastElement) {
                    this.element(element);
                }
            },
            onclick: function(element) {
                if (element.name in this.submitted)
                    this.element(element);
            },
            highlight: function(element, errorClass, validClass) {
                $(element).addClass(errorClass).removeClass(validClass);
            },
            unhighlight: function(element, errorClass, validClass) {
                $(element).removeClass(errorClass).addClass(validClass);
            }
        },

        // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
        setDefaults: function(settings) {
            $.extend($.validator.defaults, settings);
        },

        messages: {
            required: "This field is required.",
            remote: "Please fix this field.",
            email: "Please enter a valid email address.",
            url: "Please enter a valid URL.",
            date: "Please enter a valid date.",
            dateISO: "Please enter a valid date (ISO).",
            dateDE: "Bitte geben Sie ein gültiges Datum ein.",
            number: "Please enter a valid number.",
            numberDE: "Bitte geben Sie eine Nummer ein.",
            digits: "Please enter only digits",
            creditcard: "Please enter a valid credit card number.",
            equalTo: "Please enter the same value again.",
            accept: "Please enter a value with a valid extension.",
            maxlength: $.validator.format("Please enter no more than {0} characters."),
            minlength: $.validator.format("Please enter at least {0} characters."),
            rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
            range: $.validator.format("Please enter a value between {0} and {1}."),
            max: $.validator.format("Please enter a value less than or equal to {0}."),
            min: $.validator.format("Please enter a value greater than or equal to {0}.")
        },

        autoCreateRanges: false,

        prototype: {

            init: function() {
                this.labelContainer = $(this.settings.errorLabelContainer);
                this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
                this.containers = $(this.settings.errorContainer).add(this.settings.errorLabelContainer);
                this.submitted = {};
                this.valueCache = {};
                this.pendingRequest = 0;
                this.pending = {};
                this.invalid = {};
                this.reset();

                var groups = (this.groups = {});
                $.each(this.settings.groups, function(key, value) {
                    $.each(value.split(/\s/), function(index, name) {
                        groups[name] = key;
                    });
                });
                var rules = this.settings.rules;
                $.each(rules, function(key, value) {
                    rules[key] = $.validator.normalizeRule(value);
                });

                function delegate(event) {
                    var validator = $.data(this[0].form, "validator");
                    validator.settings["on" + event.type] && validator.settings["on" + event.type].call(validator, this[0]);
                }
                $(this.currentForm)
				.delegate("focusin focusout keyup", ":text, :password, :file, select, textarea", delegate)
				.delegate("click", ":radio, :checkbox", delegate);

                if (this.settings.invalidHandler)
                    $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
            },

            // http://docs.jquery.com/Plugins/Validation/Validator/form
            form: function() {
                this.checkForm();
                $.extend(this.submitted, this.errorMap);
                this.invalid = $.extend({}, this.errorMap);
                if (!this.valid())
                    $(this.currentForm).triggerHandler("invalid-form", [this]);
                this.showErrors();
                return this.valid();
            },

            checkForm: function() {
                this.prepareForm();
                for (var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++) {
                    this.check(elements[i]);
                }
                return this.valid();
            },

            // http://docs.jquery.com/Plugins/Validation/Validator/element
            element: function(element) {
                element = this.clean(element);
                this.lastElement = element;
                this.prepareElement(element);
                this.currentElements = $(element);
                var result = this.check(element);
                if (result) {
                    delete this.invalid[element.name];
                } else {
                    this.invalid[element.name] = true;
                }
                if (!this.numberOfInvalids()) {
                    // Hide error containers on last error
                    this.toHide = this.toHide.add(this.containers);
                }
                this.showErrors();
                return result;
            },

            // http://docs.jquery.com/Plugins/Validation/Validator/showErrors
            showErrors: function(errors) {
                if (errors) {
                    // add items to error list and map
                    $.extend(this.errorMap, errors);
                    this.errorList = [];
                    for (var name in errors) {
                        this.errorList.push({
                            message: errors[name],
                            element: this.findByName(name)[0]
                        });
                    }
                    // remove items from success list
                    this.successList = $.grep(this.successList, function(element) {
                        return !(element.name in errors);
                    });
                }
                this.settings.showErrors
				? this.settings.showErrors.call(this, this.errorMap, this.errorList)
				: this.defaultShowErrors();
            },

            // http://docs.jquery.com/Plugins/Validation/Validator/resetForm
            resetForm: function() {
                if ($.fn.resetForm)
                    $(this.currentForm).resetForm();
                this.submitted = {};
                this.prepareForm();
                this.hideErrors();
                this.elements().removeClass(this.settings.errorClass);
            },

            numberOfInvalids: function() {
                return this.objectLength(this.invalid);
            },

            objectLength: function(obj) {
                var count = 0;
                for (var i in obj)
                    count++;
                return count;
            },

            hideErrors: function() {
                this.addWrapper(this.toHide).hide();
            },

            valid: function() {
                return this.size() == 0;
            },

            size: function() {
                return this.errorList.length;
            },

            focusInvalid: function() {
                if (this.settings.focusInvalid) {
                    try {
                        $(this.findLastActive() || this.errorList.length && this.errorList[0].element || []).filter(":visible").focus();
                    } catch (e) {
                        // ignore IE throwing errors when focusing hidden elements
                    }
                }
            },

            findLastActive: function() {
                var lastActive = this.lastActive;
                return lastActive && $.grep(this.errorList, function(n) {
                    return n.element.name == lastActive.name;
                }).length == 1 && lastActive;
            },

            elements: function() {
                var validator = this,
				rulesCache = {};

                // select all valid inputs inside the form (no submit or reset buttons)
                // workaround $Query([]).add until http://dev.jquery.com/ticket/2114 is solved
                return $([]).add(this.currentForm.elements)
			.filter(":input")
			.not(":submit, :reset, :image, [disabled]")
			.not(this.settings.ignore)
			.filter(function() {
			    !this.name && validator.settings.debug && window.console && console.error("%o has no name assigned", this);

			    // select only the first element for each name, and only those with rules specified
			    if (this.name in rulesCache || !validator.objectLength($(this).rules()))
			        return false;

			    rulesCache[this.name] = true;
			    return true;
			});
            },

            clean: function(selector) {
                return $(selector)[0];
            },

            errors: function() {
                return $(this.settings.errorElement + "." + this.settings.errorClass, this.errorContext);
            },

            reset: function() {
                this.successList = [];
                this.errorList = [];
                this.errorMap = {};
                this.toShow = $([]);
                this.toHide = $([]);
                this.formSubmitted = false;
                this.currentElements = $([]);
            },

            prepareForm: function() {
                this.reset();
                this.toHide = this.errors().add(this.containers);
            },

            prepareElement: function(element) {
                this.reset();
                this.toHide = this.errorsFor(element);
            },

            check: function(element) {
                element = this.clean(element);

                // if radio/checkbox, validate first element in group instead
                if (this.checkable(element)) {
                    element = this.findByName(element.name)[0];
                }

                var rules = $(element).rules();
                var dependencyMismatch = false;
                for (method in rules) {
                    var rule = { method: method, parameters: rules[method] };
                    if ($.validator.methods[method]) {
                        try {

                            var result = $.validator.methods[method].call(this, element.value.replace(/\r/g, ""), element, rule.parameters);

                            // if a method indicates that the field is optional and therefore valid,
                            // don't mark it as valid when there are no other rules
                            if (result == "dependency-mismatch") {
                                dependencyMismatch = true;
                                continue;
                            }
                            dependencyMismatch = false;

                            if (result == "pending") {
                                this.toHide = this.toHide.not(this.errorsFor(element));
                                return;
                            }

                            if (!result) {
                                this.formatAndAdd(element, rule);
                                return false;
                            }
                        } catch (e) {
                            this.settings.debug && window.console && console.log("exception occured when checking element " + element.id
						 + ", check the '" + rule.method + "' method");
                            throw e;
                        }
                    }
                }
                if (dependencyMismatch)
                    return;
                if (this.objectLength(rules))
                    this.successList.push(element);
                return true;
            },

            // return the custom message for the given element and validation method
            // specified in the element's "messages" metadata
            customMetaMessage: function(element, method) {
                if (!$.metadata)
                    return;

                var meta = this.settings.meta
				? $(element).metadata()[this.settings.meta]
				: $(element).metadata();

                return meta && meta.messages && meta.messages[method];
            },

            // return the custom message for the given element name and validation method
            customMessage: function(name, method) {
                var m = this.settings.messages[name];
                return m && (m.constructor == String
				? m
				: m[method]);
            },

            // return the first defined argument, allowing empty strings
            findDefined: function() {
                for (var i = 0; i < arguments.length; i++) {
                    if (arguments[i] !== undefined)
                        return arguments[i];
                }
                return undefined;
            },

            defaultMessage: function(element, method) {
                return this.findDefined(
				this.customMessage(element.name, method),
				this.customMetaMessage(element, method),
                // title is never undefined, so handle empty string as undefined
				!this.settings.ignoreTitle && element.title || undefined,
				$.validator.messages[method],
				"<strong>Warning: No message defined for " + element.name + "</strong>"
			);
            },

            formatAndAdd: function(element, rule) {
                var message = this.defaultMessage(element, rule.method);
                if (typeof message == "function")
                    message = message.call(this, rule.parameters, element);
                this.errorList.push({
                    message: message,
                    element: element
                });
                this.errorMap[element.name] = message;
                this.submitted[element.name] = message;
            },

            addWrapper: function(toToggle) {
                if (this.settings.wrapper)
                    toToggle = toToggle.add(toToggle.parent(this.settings.wrapper));
                return toToggle;
            },

            defaultShowErrors: function() {
                for (var i = 0; this.errorList[i]; i++) {
                    var error = this.errorList[i];
                    this.settings.highlight && this.settings.highlight.call(this, error.element, this.settings.errorClass, this.settings.validClass);
                    this.showLabel(error.element, error.message);
                }
                if (this.errorList.length) {
                    this.toShow = this.toShow.add(this.containers);
                }
                if (this.settings.success) {
                    for (var i = 0; this.successList[i]; i++) {
                        this.showLabel(this.successList[i]);
                    }
                }
                if (this.settings.unhighlight) {
                    for (var i = 0, elements = this.validElements(); elements[i]; i++) {
                        this.settings.unhighlight.call(this, elements[i], this.settings.errorClass, this.settings.validClass);
                    }
                }
                this.toHide = this.toHide.not(this.toShow);
                this.hideErrors();
                this.addWrapper(this.toShow).show();
            },

            validElements: function() {
                return this.currentElements.not(this.invalidElements());
            },

            invalidElements: function() {
                return $(this.errorList).map(function() {
                    return this.element;
                });
            },

            showLabel: function(element, message) {
                var label = this.errorsFor(element);
                if (label.length) {
                    // refresh error/success class
                    label.removeClass().addClass(this.settings.errorClass);

                    // check if we have a generated label, replace the message then
                    label.attr("generated") && label.html(message);
                } else {
                    // create label
                    label = $("<" + this.settings.errorElement + "/>")
					.attr({ "for": this.idOrName(element), generated: true })
					.addClass(this.settings.errorClass)
					.html(message || "");
                    if (this.settings.wrapper) {
                        // make sure the element is visible, even in IE
                        // actually showing the wrapped element is handled elsewhere
                        label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
                    }
                    if (!this.labelContainer.append(label).length)
                        this.settings.errorPlacement
						? this.settings.errorPlacement(label, $(element))
						: label.insertAfter(element);
                }
                if (!message && this.settings.success) {
                    label.text("");
                    typeof this.settings.success == "string"
					? label.addClass(this.settings.success)
					: this.settings.success(label);
                }
                this.toShow = this.toShow.add(label);
            },

            errorsFor: function(element) {
                return this.errors().filter("[for='" + this.idOrName(element) + "']");
            },

            idOrName: function(element) {
                return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
            },

            checkable: function(element) {
                return /radio|checkbox/i.test(element.type);
            },

            findByName: function(name) {
                // select by name and filter by form for performance over form.find("[name=...]")
                var form = this.currentForm;
                return $(document.getElementsByName(name)).map(function(index, element) {
                    return element.form == form && element.name == name && element || null;
                });
            },

            getLength: function(value, element) {
                switch (element.nodeName.toLowerCase()) {
                    case 'select':
                        return $("option:selected", element).length;
                    case 'input':
                        if (this.checkable(element))
                            return this.findByName(element.name).filter(':checked').length;
                }
                return value.length;
            },

            depend: function(param, element) {
                return this.dependTypes[typeof param]
				? this.dependTypes[typeof param](param, element)
				: true;
            },

            dependTypes: {
                "boolean": function(param, element) {
                    return param;
                },
                "string": function(param, element) {
                    return !!$(param, element.form).length;
                },
                "function": function(param, element) {
                    return param(element);
                }
            },

            optional: function(element) {
                return !$.validator.methods.required.call(this, $.trim(element.value), element) && "dependency-mismatch";
            },

            startRequest: function(element) {
                if (!this.pending[element.name]) {
                    this.pendingRequest++;
                    this.pending[element.name] = true;
                }
            },

            stopRequest: function(element, valid) {
                this.pendingRequest--;
                // sometimes synchronization fails, make sure pendingRequest is never < 0
                if (this.pendingRequest < 0)
                    this.pendingRequest = 0;
                delete this.pending[element.name];
                if (valid && this.pendingRequest == 0 && this.formSubmitted && this.form()) {
                    $(this.currentForm).submit();
                } else if (!valid && this.pendingRequest == 0 && this.formSubmitted) {
                    $(this.currentForm).triggerHandler("invalid-form", [this]);
                }
            },

            previousValue: function(element) {
                return $.data(element, "previousValue") || $.data(element, "previousValue", previous = {
                    old: null,
                    valid: true,
                    message: this.defaultMessage(element, "remote")
                });
            }

        },

        classRuleSettings: {
            required: { required: true },
            email: { email: true },
            url: { url: true },
            date: { date: true },
            dateISO: { dateISO: true },
            dateDE: { dateDE: true },
            number: { number: true },
            numberDE: { numberDE: true },
            digits: { digits: true },
            creditcard: { creditcard: true }
        },

        addClassRules: function(className, rules) {
            className.constructor == String ?
			this.classRuleSettings[className] = rules :
			$.extend(this.classRuleSettings, className);
        },

        classRules: function(element) {
            var rules = {};
            var classes = $(element).attr('class');
            classes && $.each(classes.split(' '), function() {
                if (this in $.validator.classRuleSettings) {
                    $.extend(rules, $.validator.classRuleSettings[this]);
                }
            });
            return rules;
        },

        attributeRules: function(element) {
            var rules = {};
            var $element = $(element);

            for (method in $.validator.methods) {
                var value = $element.attr(method);
                if (value) {
                    rules[method] = value;
                }
            }

            // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
            if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) {
                delete rules.maxlength;
            }

            return rules;
        },

        metadataRules: function(element) {
            if (!$.metadata) return {};

            var meta = $.data(element.form, 'validator').settings.meta;
            return meta ?
			$(element).metadata()[meta] :
			$(element).metadata();
        },

        staticRules: function(element) {
            var rules = {};
            var validator = $.data(element.form, 'validator');
            if (validator.settings.rules) {
                rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
            }
            return rules;
        },

        normalizeRules: function(rules, element) {
            // handle dependency check
            $.each(rules, function(prop, val) {
                // ignore rule when param is explicitly false, eg. required:false
                if (val === false) {
                    delete rules[prop];
                    return;
                }
                if (val.param || val.depends) {
                    var keepRule = true;
                    switch (typeof val.depends) {
                        case "string":
                            keepRule = !!$(val.depends, element.form).length;
                            break;
                        case "function":
                            keepRule = val.depends.call(element, element);
                            break;
                    }
                    if (keepRule) {
                        rules[prop] = val.param !== undefined ? val.param : true;
                    } else {
                        delete rules[prop];
                    }
                }
            });

            // evaluate parameters
            $.each(rules, function(rule, parameter) {
                rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
            });

            // clean number parameters
            $.each(['minlength', 'maxlength', 'min', 'max'], function() {
                if (rules[this]) {
                    rules[this] = Number(rules[this]);
                }
            });
            $.each(['rangelength', 'range'], function() {
                if (rules[this]) {
                    rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
                }
            });

            if ($.validator.autoCreateRanges) {
                // auto-create ranges
                if (rules.min && rules.max) {
                    rules.range = [rules.min, rules.max];
                    delete rules.min;
                    delete rules.max;
                }
                if (rules.minlength && rules.maxlength) {
                    rules.rangelength = [rules.minlength, rules.maxlength];
                    delete rules.minlength;
                    delete rules.maxlength;
                }
            }

            // To support custom messages in metadata ignore rule methods titled "messages"
            if (rules.messages) {
                delete rules.messages
            }

            return rules;
        },

        // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
        normalizeRule: function(data) {
            if (typeof data == "string") {
                var transformed = {};
                $.each(data.split(/\s/), function() {
                    transformed[this] = true;
                });
                data = transformed;
            }
            return data;
        },

        // http://docs.jquery.com/Plugins/Validation/Validator/addMethod
        addMethod: function(name, method, message) {
            $.validator.methods[name] = method;
            $.validator.messages[name] = message || $.validator.messages[name];
            if (method.length < 3) {
                $.validator.addClassRules(name, $.validator.normalizeRule(name));
            }
        },

        methods: {

            // http://docs.jquery.com/Plugins/Validation/Methods/required
            required: function(value, element, param) {
                // check if dependency is met
                if (!this.depend(param, element))
                    return "dependency-mismatch";
                switch (element.nodeName.toLowerCase()) {
                    case 'select':
                        var options = $("option:selected", element);
                        return options.length > 0 && (element.type == "select-multiple" || ($.browser.msie && !(options[0].attributes['value'].specified) ? options[0].text : options[0].value).length > 0);
                    case 'input':
                        if (this.checkable(element))
                            return this.getLength(value, element) > 0;
                    default:
                        return $.trim(value).length > 0;
                }
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/remote
            remote: function(value, element, param) {
                if (this.optional(element))
                    return "dependency-mismatch";

                var previous = this.previousValue(element);

                if (!this.settings.messages[element.name])
                    this.settings.messages[element.name] = {};
                this.settings.messages[element.name].remote = typeof previous.message == "function" ? previous.message(value) : previous.message;

                param = typeof param == "string" && { url: param} || param;

                if (previous.old !== value) {
                    previous.old = value;
                    var validator = this;
                    this.startRequest(element);
                    var data = {};
                    data[element.name] = value;
                    $.ajax($.extend(true, {
                        url: param,
                        mode: "abort",
                        port: "validate" + element.name,
                        dataType: "json",
                        data: data,
                        success: function(response) {
                            var valid = response === true;
                            if (valid) {
                                var submitted = validator.formSubmitted;
                                validator.prepareElement(element);
                                validator.formSubmitted = submitted;
                                validator.successList.push(element);
                                validator.showErrors();
                            } else {
                                var errors = {};
                                errors[element.name] = previous.message = response || validator.defaultMessage(element, "remote");
                                validator.showErrors(errors);
                            }
                            previous.valid = valid;
                            validator.stopRequest(element, valid);
                        }
                    }, param));
                    return "pending";
                } else if (this.pending[element.name]) {
                    return "pending";
                }
                return previous.valid;
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/minlength
            minlength: function(value, element, param) {
                return this.optional(element) || this.getLength($.trim(value), element) >= param;
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/maxlength
            maxlength: function(value, element, param) {
                return this.optional(element) || this.getLength($.trim(value), element) <= param;
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/rangelength
            rangelength: function(value, element, param) {
                var length = this.getLength($.trim(value), element);
                return this.optional(element) || (length >= param[0] && length <= param[1]);
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/min
            min: function(value, element, param) {
                return this.optional(element) || value >= param;
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/max
            max: function(value, element, param) {
                return this.optional(element) || value <= param;
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/range
            range: function(value, element, param) {
                return this.optional(element) || (value >= param[0] && value <= param[1]);
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/email
            email: function(value, element) {
                // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
                return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(value);
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/url
            url: function(value, element) {
                // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
                return this.optional(element) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/date
            date: function(value, element) {
                return this.optional(element) || !/Invalid|NaN/.test(new Date(value));
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/dateISO
            dateISO: function(value, element) {
                return this.optional(element) || /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value);
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/dateDE
            dateDE: function(value, element) {
                return this.optional(element) || /^\d\d?\.\d\d?\.\d\d\d?\d?$/.test(value);
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/number
            number: function(value, element) {
                return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value);
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/numberDE
            numberDE: function(value, element) {
                return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:\.\d{3})+)(?:,\d+)?$/.test(value);
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/digits
            digits: function(value, element) {
                return this.optional(element) || /^\d+$/.test(value);
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/creditcard
            // based on http://en.wikipedia.org/wiki/Luhn
            creditcard: function(value, element) {
                if (this.optional(element))
                    return "dependency-mismatch";
                // accept only digits and dashes
                if (/[^0-9-]+/.test(value))
                    return false;
                var nCheck = 0,
				nDigit = 0,
				bEven = false;

                value = value.replace(/\D/g, "");

                for (n = value.length - 1; n >= 0; n--) {
                    var cDigit = value.charAt(n);
                    var nDigit = parseInt(cDigit, 10);
                    if (bEven) {
                        if ((nDigit *= 2) > 9)
                            nDigit -= 9;
                    }
                    nCheck += nDigit;
                    bEven = !bEven;
                }

                return (nCheck % 10) == 0;
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/accept
            accept: function(value, element, param) {
                param = typeof param == "string" ? param.replace(/,/g, '|') : "png|jpe?g|gif";
                return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i"));
            },

            // http://docs.jquery.com/Plugins/Validation/Methods/equalTo
            equalTo: function(value, element, param) {
                return value == $(param).val();
            }

        }

    });

    // deprecated, use $.validator.format instead
    $.format = $.validator.format;

})(jQuery);

// ajax mode: abort
// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() 
; (function($) {
    var ajax = $.ajax;
    var pendingRequests = {};
    $.ajax = function(settings) {
        // create settings for compatibility with ajaxSetup
        settings = $.extend(settings, $.extend({}, $.ajaxSettings, settings));
        var port = settings.port;
        if (settings.mode == "abort") {
            if (pendingRequests[port]) {
                pendingRequests[port].abort();
            }
            return (pendingRequests[port] = ajax.apply(this, arguments));
        }
        return ajax.apply(this, arguments);
    };
})(jQuery);

// provides cross-browser focusin and focusout events
// IE has native support, in other browsers, use event caputuring (neither bubbles)

// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target 

// provides triggerEvent(type: String, target: Element) to trigger delegated events
; (function($) {
    $.each({
        focus: 'focusin',
        blur: 'focusout'
    }, function(original, fix) {
        $.event.special[fix] = {
            setup: function() {
                if ($.browser.msie) return false;
                this.addEventListener(original, $.event.special[fix].handler, true);
            },
            teardown: function() {
                if ($.browser.msie) return false;
                this.removeEventListener(original,
				$.event.special[fix].handler, true);
            },
            handler: function(e) {
                arguments[0] = $.event.fix(e);
                arguments[0].type = fix;
                return $.event.handle.apply(this, arguments);
            }
        };
    });
    $.extend($.fn, {
        delegate: function(type, delegate, handler) {
            return this.bind(type, function(event) {
                var target = $(event.target);
                if (target.is(delegate)) {
                    return handler.apply(target, arguments);
                }
            });
        },
        triggerEvent: function(type, target) {
            return this.triggerHandler(type, [$.event.fix({ type: type, target: target })]);
        }
    })
})(jQuery);

/*
 * Metadata - jQuery plugin for parsing metadata from elements
 *
 * Copyright (c) 2006 John Resig, Yehuda Katz, J�örn Zaefferer, Paul McLanahan
 *
 * 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.metadata.js 3620 2007-10-10 20:55:38Z pmclanahan $
 *
 */
(function($){$.extend({metadata:{defaults:{type:'class',name:'metadata',cre:/({.*})/,single:'metadata'},setType:function(type,name){this.defaults.type=type;this.defaults.name=name;},get:function(elem,opts){var settings=$.extend({},this.defaults,opts);if(!settings.single.length)settings.single='metadata';var data=$.data(elem,settings.single);if(data)return data;data="{}";if(settings.type=="class"){var m=settings.cre.exec(elem.className);if(m)data=m[1];}else if(settings.type=="elem"){if(!elem.getElementsByTagName)return;var e=elem.getElementsByTagName(settings.name);if(e.length)data=$.trim(e[0].innerHTML);}else if(elem.getAttribute!=undefined){var attr=elem.getAttribute(settings.name);if(attr)data=attr;}if(data.indexOf('{')<0)data="{"+data+"}";data=eval("("+data+")");$.data(elem,settings.single,data);return data;}}});$.fn.metadata=function(opts){return $.metadata.get(this[0],opts);};})(jQuery);
/*
 * 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);
	},
	onchange: function(handler) {
		return this.bind("onchange", 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) {
		$input.trigger("onchange",[]);
		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: 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);
/*
 *
 * Copyright (c) 2006-2008 Sam Collett (http://www.texotela.co.uk)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * Version 2.2.3
 * Demo: http://www.texotela.co.uk/code/jquery/select/
 *
 * $LastChangedDate: 2008-06-17 17:27:25 +0100 (Tue, 17 Jun 2008) $
 * $Rev: 5727 $
 *
 */
;(function($){$.fn.addOption=function(){var e=function(a,v,t,b){var c=document.createElement("option");c.value=v,c.text=t;var o=a.options;var d=o.length;if(!a.cache){a.cache={};for(var i=0;i<d;i++){a.cache[o[i].value]=i}}if(typeof a.cache[v]=="undefined")a.cache[v]=d;a.options[a.cache[v]]=c;if(b){c.selected=true}};var a=arguments;if(a.length==0)return this;var f=true;var m=false;var g,v,t;if(typeof(a[0])=="object"){m=true;g=a[0]}if(a.length>=2){if(typeof(a[1])=="boolean")f=a[1];else if(typeof(a[2])=="boolean")f=a[2];if(!m){v=a[0];t=a[1]}}this.each(function(){if(this.nodeName.toLowerCase()!="select")return;if(m){for(var a in g){e(this,a,g[a],f)}}else{e(this,v,t,f)}});return this};$.fn.ajaxAddOption=function(b,c,d,e,f){if(typeof(b)!="string")return this;if(typeof(c)!="object")c={};if(typeof(d)!="boolean")d=true;this.each(function(){var a=this;$.getJSON(b,c,function(r){$(a).addOption(r,d);if(typeof e=="function"){if(typeof f=="object"){e.apply(a,f)}else{e.call(a)}}})});return this};$.fn.removeOption=function(){var a=arguments;if(a.length==0)return this;var d=typeof(a[0]);var v,index;if(d=="string"||d=="object"||d=="function"){v=a[0];if(v.constructor==Array){var l=v.length;for(var i=0;i<l;i++){this.removeOption(v[i],a[1])}return this}}else if(d=="number")index=a[0];else return this;this.each(function(){if(this.nodeName.toLowerCase()!="select")return;if(this.cache)this.cache=null;var b=false;var o=this.options;if(!!v){var c=o.length;for(var i=c-1;i>=0;i--){if(v.constructor==RegExp){if(o[i].value.match(v)){b=true}}else if(o[i].value==v){b=true}if(b&&a[1]===true)b=o[i].selected;if(b){o[i]=null}b=false}}else{if(a[1]===true){b=o[index].selected}else{b=true}if(b){this.remove(index)}}});return this};$.fn.sortOptions=function(f){var a=typeof(f)=="undefined"?true:!!f;this.each(function(){if(this.nodeName.toLowerCase()!="select")return;var o=this.options;var d=o.length;var e=[];for(var i=0;i<d;i++){e[i]={v:o[i].value,t:o[i].text}}e.sort(function(b,c){o1t=b.t.toLowerCase(),o2t=c.t.toLowerCase();if(o1t==o2t)return 0;if(a){return o1t<o2t?-1:1}else{return o1t>o2t?-1:1}});for(var i=0;i<d;i++){o[i].text=e[i].t;o[i].value=e[i].v}});return this};$.fn.selectOptions=function(b,d){var v=b;var e=typeof(b);var c=d||false;if(e!="string"&&e!="function"&&e!="object")return this;this.each(function(){if(this.nodeName.toLowerCase()!="select")return this;var o=this.options;var a=o.length;for(var i=0;i<a;i++){if(v.constructor==RegExp){if(o[i].value.match(v)){o[i].selected=true}else if(c){o[i].selected=false}}else{if(o[i].value==v){o[i].selected=true}else if(c){o[i].selected=false}}}});return this};$.fn.copyOptions=function(b,c){var w=c||"selected";if($(b).size()==0)return this;this.each(function(){if(this.nodeName.toLowerCase()!="select")return this;var o=this.options;var a=o.length;for(var i=0;i<a;i++){if(w=="all"||(w=="selected"&&o[i].selected)){$(b).addOption(o[i].value,o[i].text)}}});return this};$.fn.containsOption=function(b,c){var d=false;var v=b;var e=typeof(v);var f=typeof(c);if(e!="string"&&e!="function"&&e!="object")return f=="function"?this:d;this.each(function(){if(this.nodeName.toLowerCase()!="select")return this;if(d&&f!="function")return false;var o=this.options;var a=o.length;for(var i=0;i<a;i++){if(v.constructor==RegExp){if(o[i].value.match(v)){d=true;if(f=="function")c.call(o[i],i)}}else{if(o[i].value==v){d=true;if(f=="function")c.call(o[i],i)}}}});return f=="function"?this:d};$.fn.selectedValues=function(){var v=[];this.find("option:selected").each(function(){v[v.length]=this.value});return v};$.fn.selectedOptions=function(){return this.find("option:selected")}})(jQuery);
/**
 * SearchHighlight plugin for jQuery
 * 
 * Thanks to Scott Yang <http://scott.yang.id.au/>
 * for the original idea and some code
 *    
 * @author Renato Formato <renatoformato@virgilio.it> 
 *  
 * @version 0.33
 *
 *  Options
 *  - exact (string, default:"exact") 
 *    "exact" : find and highlight the exact words.
 *    "whole" : find partial matches but highlight whole words
 *    "partial": find and highlight partial matches
 *     
 *  - style_name (string, default:'hilite')
 *    The class given to the span wrapping the matched words.
 *     
 *  - style_name_suffix (boolean, default:true)
 *    If true a different number is added to style_name for every different matched word.
 *     
 *  - debug_referrer (string, default:null)
 *    Set a referrer for debugging purpose.
 *     
 *  - engines (array of regex, default:null)
 *    Add a new search engine regex to highlight searches coming from new search engines.
 *    The first element is the regex to match the domain.
 *    The second element is the regex to match the query string. 
 *    Ex: [/^http:\/\/my\.site\.net/i,/search=([^&]+)/i]        
 *            
 *  - highlight (string, default:null)
 *    A jQuery selector or object to set the elements enabled for highlight.
 *    If null or no elements are found, all the document is enabled for highlight.
 *        
 *  - nohighlight (string, default:null)  
 *    A jQuery selector or object to set the elements not enabled for highlight.
 *    This option has priority on highlight. 
 *    
 *  - keys (string, default:null)
 *    Disable the analisys of the referrer and search for the words given as argument    
 *    
 */

(function($){
  jQuery.fn.SearchHighlight = function(options) {
    var ref = options.debug_referrer || document.referrer;
    if(!ref && options.keys==undefined) return this;
    
    SearchHighlight.options = $.extend({exact:"exact",style_name:'hilite',style_name_suffix:true},options);
    
    if(options.engines) SearchHighlight.engines.unshift(options.engines);  
    var q = options.keys!=undefined?options.keys.toLowerCase().split(/[\s,\+\.]+/):SearchHighlight.decodeURL(ref,SearchHighlight.engines);
    if(q && q.join("")) {
      SearchHighlight.buildReplaceTools(q);
      return this.each(function(){
        var el = this;
        if(el==document) el = $("body")[0];
        SearchHighlight.hiliteElement(el, q); 
      })
    } else return this;
  }    

  var SearchHighlight = {
    options: {},
    regex: [],
    engines: [
    [/^http:\/\/(www\.)?google\./i, /q=([^&]+)/i],                            // Google
    [/^http:\/\/(www\.)?search\.yahoo\./i, /p=([^&]+)/i],                     // Yahoo
    [/^http:\/\/(www\.)?search\.msn\./i, /q=([^&]+)/i],                       // MSN
    [/^http:\/\/(www\.)?search\.live\./i, /query=([^&]+)/i],                  // MSN Live
    [/^http:\/\/(www\.)?search\.aol\./i, /userQuery=([^&]+)/i],               // AOL
    [/^http:\/\/(www\.)?ask\.com/i, /q=([^&]+)/i],                            // Ask.com
    [/^http:\/\/(www\.)?altavista\./i, /q=([^&]+)/i],                         // AltaVista
    [/^http:\/\/(www\.)?feedster\./i, /q=([^&]+)/i],                          // Feedster
    [/^http:\/\/(www\.)?search\.lycos\./i, /q=([^&]+)/i],                     // Lycos
    [/^http:\/\/(www\.)?alltheweb\./i, /q=([^&]+)/i],                         // AllTheWeb
    [/^http:\/\/(www\.)?technorati\.com/i, /([^\?\/]+)(?:\?.*)$/i],           // Technorati
    ],
    subs: {},
    decodeURL: function(URL,reg) {
      URL = decodeURIComponent(URL);
      var query = null;
      $.each(reg,function(i,n){
        if(n[0].test(URL)) {
          var match = URL.match(n[1]);
          if(match) {
            query = match[1].toLowerCase();
            return false;
          }
        }
      })
      
      if (query) {
      query = query.replace(/(\'|")/, '\$1');
      query = query.split(/[\s,\+\.]+/);
      }
      
      return query;
    },
		regexAccent : [
      [/[\xC0-\xC5\u0100-\u0105]/ig,'a'],
      [/[\xC7\u0106-\u010D]/ig,'c'],
      [/[\xC8-\xCB]/ig,'e'],
      [/[\xCC-\xCF]/ig,'i'],
      [/\xD1/ig,'n'],
      [/[\xD2-\xD6\xD8]/ig,'o'],
      [/[\u015A-\u0161]/ig,'s'],
      [/[\u0162-\u0167]/ig,'t'],
      [/[\xD9-\xDC]/ig,'u'],
      [/\xFF/ig,'y'],
      [/[\x91\x92\u2018\u2019]/ig,'\'']
    ],
    matchAccent : /[\x91\x92\xC0-\xC5\xC7-\xCF\xD1-\xD6\xD8-\xDC\xFF\u0100-\u010D\u015A-\u0167\u2018\u2019]/ig,  
		replaceAccent: function(q) {
		  SearchHighlight.matchAccent.lastIndex = 0;
      if(SearchHighlight.matchAccent.test(q)) {
        for(var i=0,l=SearchHighlight.regexAccent.length;i<l;i++)
          q = q.replace(SearchHighlight.regexAccent[i][0],SearchHighlight.regexAccent[i][1]);
      }
      return q;
    },
    escapeRegEx : /((?:\\{2})*)([[\]{}*?|])/g, //the special chars . and + are already gone at this point because they are considered split chars
    buildReplaceTools : function(query) {
        var re = [], regex;
        $.each(query,function(i,n){
            if(n = SearchHighlight.replaceAccent(n).replace(SearchHighlight.escapeRegEx,"$1\\$2"))
              re.push(n);        
        });
        
        regex = re.join("|");
        switch(SearchHighlight.options.exact) {
          case "exact":
            regex = '\\b(?:'+regex+')\\b';
            break;
          case "whole":
            regex = '\\b\\w*('+regex+')\\w*\\b';
            break;
        }    
        SearchHighlight.regex = new RegExp(regex, "gi");
        
        $.each(re,function(i,n){
            SearchHighlight.subs[n] = SearchHighlight.options.style_name+
              (SearchHighlight.options.style_name_suffix?i+1:''); 
        });       
    },
    nosearch: /s(?:cript|tyle)|textarea/i,
    hiliteElement: function(el, query) {
        var opt = SearchHighlight.options, elHighlight, noHighlight;
        elHighlight = opt.highlight?$(opt.highlight):$("body"); 
        if(!elHighlight.length) elHighlight = $("body"); 
        noHighlight = opt.nohighlight?$(opt.nohighlight):$([]);
                
        elHighlight.each(function(){
          SearchHighlight.hiliteTree(this,query,noHighlight);
        });
    },
    hiliteTree : function(el,query,noHighlight) {
        if(noHighlight.index(el)!=-1) return;
        var matchIndex = SearchHighlight.options.exact=="whole"?1:0;
        for(var startIndex=0,endIndex=el.childNodes.length;startIndex<endIndex;startIndex++) {
          var item = el.childNodes[startIndex];
          if ( item.nodeType != 8 ) {//comment node
  				  //text node
            if(item.nodeType==3) {
              var text = item.data, textNoAcc = SearchHighlight.replaceAccent(text);
              var newtext="",match,index=0;
              SearchHighlight.regex.lastIndex = 0;
              while(match = SearchHighlight.regex.exec(textNoAcc)) {
                newtext += text.substr(index,match.index-index)+'<span class="'+
                SearchHighlight.subs[match[matchIndex].toLowerCase()]+'">'+text.substr(match.index,match[0].length)+"</span>";
                index = match.index+match[0].length;
              }
              if(newtext) {
                //add the last part of the text
                newtext += text.substring(index);
                var repl = $.merge([],$("<span>"+newtext+"</span>")[0].childNodes);
                endIndex += repl.length-1;
                startIndex += repl.length-1;
                $(item).before(repl).remove();
              }                
            } else {
              if(item.nodeType==1 && item.nodeName.search(SearchHighlight.nosearch)==-1)
                  SearchHighlight.hiliteTree(item,query,noHighlight);
            }	
          }
        }    
    }
  };
})(jQuery)

/*
 * jQuery UI 1.6b
 *
 * Copyright (c) 2008 Paul Bakaus (ui.jquery.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI
 */
;(function($) {

// This adds a selector to check if data exists.
jQuery.extend(jQuery.expr[':'], { 
	data: "jQuery.data(a, m[3])"
});

$.ui = {
	plugin: {
		add: function(module, option, set) {
			var proto = $.ui[module].prototype;
			for(var i in set) {
				proto.plugins[i] = proto.plugins[i] || [];
				proto.plugins[i].push([option, set[i]]);
			}
		},
		call: function(instance, name, args) {
			var set = instance.plugins[name];
			if(!set) { return; }
			
			for (var i = 0; i < set.length; i++) {
				if (instance.options[set[i][0]]) {
					set[i][1].apply(instance.element, args);
				}
			}
		}	
	},
	cssCache: {},
	css: function(name) {
		if ($.ui.cssCache[name]) { return $.ui.cssCache[name]; }
		var tmp = $('<div class="ui-gen">').addClass(name).css({position:'absolute', top:'-5000px', left:'-5000px', display:'block'}).appendTo('body');
		
		//if (!$.browser.safari)
			//tmp.appendTo('body'); 
		
		//Opera and Safari set width and height to 0px instead of auto
		//Safari returns rgba(0,0,0,0) when bgcolor is not set
		$.ui.cssCache[name] = !!(
			(!(/auto|default/).test(tmp.css('cursor')) || (/^[1-9]/).test(tmp.css('height')) || (/^[1-9]/).test(tmp.css('width')) || 
			!(/none/).test(tmp.css('backgroundImage')) || !(/transparent|rgba\(0, 0, 0, 0\)/).test(tmp.css('backgroundColor')))
		);
		try { $('body').get(0).removeChild(tmp.get(0));	} catch(e){}
		return $.ui.cssCache[name];
	},
	disableSelection: function(el) {
		$(el).attr('unselectable', 'on').css('MozUserSelect', 'none').bind('selectstart', function() { return false; });
	},
	enableSelection: function(el) {
		$(el).attr('unselectable', 'off').css('MozUserSelect', '').unbind('selectstart');
	},
	hasScroll: function(e, a) {
		var scroll = (a && a == 'left') ? 'scrollLeft' : 'scrollTop',
			has = false;
		
		if (e[scroll] > 0) { return true; }
		
		// TODO: determine which cases actually cause this to happen
		// if the element doesn't have the scroll set, see if it's possible to
		// set the scroll
		e[scroll] = 1;
		has = (e[scroll] > 0);
		e[scroll] = 0;
		return has;
	}
};


/** jQuery core modifications and additions **/

var _remove = $.fn.remove;
$.fn.remove = function() {
	$("*", this).add(this).triggerHandler("remove");
	return _remove.apply(this, arguments );
};

// $.widget is a factory to create jQuery plugins
// taking some boilerplate code out of the plugin code
// created by Scott González and Jörn Zaefferer
function getter(namespace, plugin, method) {
	var methods = $[namespace][plugin].getter || [];
	methods = (typeof methods == "string" ? methods.split(/,?\s+/) : methods);
	return ($.inArray(method, methods) != -1);
}

$.widget = function(name, prototype) {
	var namespace = name.split(".")[0];
	name = name.split(".")[1];
	
	// create plugin method
	$.fn[name] = function(options) {
		var isMethodCall = (typeof options == 'string'),
			args = Array.prototype.slice.call(arguments, 1);
		
		if (isMethodCall && getter(namespace, name, options)) {
			var instance = $.data(this[0], name);
			return (instance ? instance[options].apply(instance, args)
				: undefined);
		}
		
		return this.each(function() {
			var instance = $.data(this, name);
			if (isMethodCall && instance && $.isFunction(instance[options])) {
				instance[options].apply(instance, args);
			} else if (!isMethodCall) {
				$.data(this, name, new $[namespace][name](this, options));
			}
		});
	};
	
	// create widget constructor
	$[namespace][name] = function(element, options) {
		var self = this;
		
		this.widgetName = name;
		this.widgetEventPrefix = $[namespace][name].eventPrefix || name;
		this.widgetBaseClass = namespace + '-' + name;
		
		this.options = $.extend({}, $.widget.defaults, $[namespace][name].defaults, options);
		this.element = $(element)
			.bind('setData.' + name, function(e, key, value) {
				return self.setData(key, value);
			})
			.bind('getData.' + name, function(e, key) {
				return self.getData(key);
			})
			.bind('remove', function() {
				return self.destroy();
			});
		this.init();
	};
	
	// add widget prototype
	$[namespace][name].prototype = $.extend({}, $.widget.prototype, prototype);
};

$.widget.prototype = {
	init: function() {},
	destroy: function() {
		this.element.removeData(this.widgetName);
	},
	
	getData: function(key) {
		return this.options[key];
	},
	setData: function(key, value) {
		this.options[key] = value;
		
		if (key == 'disabled') {
			this.element[value ? 'addClass' : 'removeClass'](
				this.widgetBaseClass + '-disabled');
		}
	},
	
	enable: function() {
		this.setData('disabled', false);
	},
	disable: function() {
		this.setData('disabled', true);
	},
	
	trigger: function(type, e, data) {
		var eventName = (type == this.widgetEventPrefix
			? type : this.widgetEventPrefix + type);
		e = e  || $.event.fix({ type: eventName, target: this.element[0] });
		return this.element.triggerHandler(eventName, [e, data], this.options[type]);
	}
};

$.widget.defaults = {
	disabled: false
};


/** Mouse Interaction Plugin **/

$.ui.mouse = {
	mouseInit: function() {
		var self = this;
	
		this.element.bind('mousedown.'+this.widgetName, function(e) {
			return self.mouseDown(e);
		});
		
		// Prevent text selection in IE
		if ($.browser.msie) {
			this._mouseUnselectable = this.element.attr('unselectable');
			this.element.attr('unselectable', 'on');
		}
		
		this.started = false;
	},
	
	// TODO: make sure destroying one instance of mouse doesn't mess with
	// other instances of mouse
	mouseDestroy: function() {
		this.element.unbind('.'+this.widgetName);
		
		// Restore text selection in IE
		($.browser.msie
			&& this.element.attr('unselectable', this._mouseUnselectable));
	},
	
	mouseDown: function(e) {
		// we may have missed mouseup (out of window)
		(this._mouseStarted && this.mouseUp(e));
		
		this._mouseDownEvent = e;
		
		var self = this,
			btnIsLeft = (e.which == 1),
			elIsCancel = (typeof this.options.cancel == "string" ? $(e.target).parents().add(e.target).filter(this.options.cancel).length : false);
		if (!btnIsLeft || elIsCancel || !this.mouseCapture(e)) {
			return true;
		}
		
		this._mouseDelayMet = !this.options.delay;
		if (!this._mouseDelayMet) {
			this._mouseDelayTimer = setTimeout(function() {
				self._mouseDelayMet = true;
			}, this.options.delay);
		}
		
		if (this.mouseDistanceMet(e) && this.mouseDelayMet(e)) {
			this._mouseStarted = (this.mouseStart(e) !== false);
			if (!this._mouseStarted) {
				e.preventDefault();
				return true;
			}
		}
		
		// these delegates are required to keep context
		this._mouseMoveDelegate = function(e) {
			return self.mouseMove(e);
		};
		this._mouseUpDelegate = function(e) {
			return self.mouseUp(e);
		};
		$(document)
			.bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
			.bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
		
		return false;
	},
	
	mouseMove: function(e) {
		// IE mouseup check - mouseup happened when mouse was out of window
		if ($.browser.msie && !e.button) {
			return this.mouseUp(e);
		}
		
		if (this._mouseStarted) {
			this.mouseDrag(e);
			return false;
		}
		
		if (this.mouseDistanceMet(e) && this.mouseDelayMet(e)) {
			this._mouseStarted =
				(this.mouseStart(this._mouseDownEvent, e) !== false);
			(this._mouseStarted ? this.mouseDrag(e) : this.mouseUp(e));
		}
		
		return !this._mouseStarted;
	},
	
	mouseUp: function(e) {
		$(document)
			.unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
			.unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
		
		if (this._mouseStarted) {
			this._mouseStarted = false;
			this.mouseStop(e);
		}
		
		return false;
	},
	
	mouseDistanceMet: function(e) {
		return (Math.max(
				Math.abs(this._mouseDownEvent.pageX - e.pageX),
				Math.abs(this._mouseDownEvent.pageY - e.pageY)
			) >= this.options.distance
		);
	},
	
	mouseDelayMet: function(e) {
		return this._mouseDelayMet;
	},
	
	// These are placeholder methods, to be overriden by extending plugin
	mouseStart: function(e) {},
	mouseDrag: function(e) {},
	mouseStop: function(e) {},
	mouseCapture: function(e) { return true; }
};

$.ui.mouse.defaults = {
	cancel: null,
	distance: 1,
	delay: 0
};

})(jQuery);

/*
 * jQuery UI Dialog
 *
 * Copyright (c) 2008 Richard D. Worth (rdworth.org)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 * 
 * http://docs.jquery.com/UI/Dialog
 *
 * Depends:
 *	ui.core.js
 *	ui.draggable.js
 *	ui.resizable.js
 */
(function($) {

var setDataSwitch = {
	dragStart: "start.draggable",
	drag: "drag.draggable",
	dragStop: "stop.draggable",
	maxHeight: "maxHeight.resizable",
	minHeight: "minHeight.resizable",
	maxWidth: "maxWidth.resizable",
	minWidth: "minWidth.resizable",
	resizeStart: "start.resizable",
	resize: "drag.resizable",
	resizeStop: "stop.resizable"
};

$.widget("ui.dialog", {
	init: function() {
		this.options.title = this.options.title || this.element.attr('title');
		
		var self = this,
			options = this.options,
			resizeHandles = typeof options.resizable == 'string'
				? options.resizable
				: 'n,e,s,w,se,sw,ne,nw',
			
			uiDialogContent = this.element
				.addClass('ui-dialog-content')
				.wrap('<div/>')
				.wrap('<div/>'),
			
			uiDialogContainer = (this.uiDialogContainer = uiDialogContent.parent())
				.addClass('ui-dialog-container')
				.css({
					position: 'relative',
					width: '100%',
					height: '100%'
				}),
			
			title = options.title || '&nbsp;',
			uiDialogTitlebar = (this.uiDialogTitlebar =
				$('<div class="ui-dialog-titlebar"/>'))
				.append('<span class="ui-dialog-title">' + title + '</span>')
				.append('<a href="#" class="ui-dialog-titlebar-close"><span>X</span></a>')
				.prependTo(uiDialogContainer),
			
			uiDialog = (this.uiDialog = uiDialogContainer.parent())
				.appendTo(document.body)
				.hide()
				.addClass('ui-dialog')
				.addClass(options.dialogClass)
				// add content classes to dialog
				// to inherit theme at top level of element
				.addClass(uiDialogContent.attr('className'))
					.removeClass('ui-dialog-content')
				.css({
					position: 'absolute',
					width: options.width,
					height: options.height,
					overflow: 'hidden',
					zIndex: options.zIndex
				})
				// setting tabIndex makes the div focusable
				// setting outline to 0 prevents a border on focus in Mozilla
				.attr('tabIndex', -1).css('outline', 0).keydown(function(ev) {
					if (options.closeOnEscape) {
						var ESC = 27;
						(ev.keyCode && ev.keyCode == ESC && self.close());
					}
				})
				.mousedown(function() {
					self.moveToTop();
				}),
			
			uiDialogButtonPane = (this.uiDialogButtonPane = $('<div/>'))
				.addClass('ui-dialog-buttonpane')
				.css({
					position: 'absolute',
					bottom: 0
				})
				.appendTo(uiDialog);
		
		this.uiDialogTitlebarClose = $('.ui-dialog-titlebar-close', uiDialogTitlebar)
			.hover(
				function() {
					$(this).addClass('ui-dialog-titlebar-close-hover');
				},
				function() {
					$(this).removeClass('ui-dialog-titlebar-close-hover');
				}
			)
			.mousedown(function(ev) {
				ev.stopPropagation();
			})
			.click(function() {
				self.close();
				return false;
			});
		
		uiDialogTitlebar.find("*").add(uiDialogTitlebar).each(function() {
			$.ui.disableSelection(this);
		});
		
		if ($.fn.draggable) {
			uiDialog.draggable({
				cancel: '.ui-dialog-content',
				helper: options.dragHelper,
				handle: '.ui-dialog-titlebar',
				start: function() {
					self.moveToTop();
					(options.dragStart && options.dragStart.apply(self.element[0], arguments));
				},
				drag: function() {
					(options.drag && options.drag.apply(self.element[0], arguments));
				},
				stop: function() {
					(options.dragStop && options.dragStop.apply(self.element[0], arguments));
					$.ui.dialog.overlay.resize();
				}
			});
			(options.draggable || uiDialog.draggable('disable'));
		}
		
		if ($.fn.resizable) {
			uiDialog.resizable({
				cancel: '.ui-dialog-content',
				helper: options.resizeHelper,
				maxWidth: options.maxWidth,
				maxHeight: options.maxHeight,
				minWidth: options.minWidth,
				minHeight: options.minHeight,
				start: function() {
					(options.resizeStart && options.resizeStart.apply(self.element[0], arguments));
				},
				resize: function() {
					(options.autoResize && self.size.apply(self));
					(options.resize && options.resize.apply(self.element[0], arguments));
				},
				handles: resizeHandles,
				stop: function() {
					(options.autoResize && self.size.apply(self));
					(options.resizeStop && options.resizeStop.apply(self.element[0], arguments));
					$.ui.dialog.overlay.resize();
				}
			});
			(options.resizable || uiDialog.resizable('disable'));
		}
		
		this.createButtons(options.buttons);
		this.isOpen = false;
		
		(options.bgiframe && $.fn.bgiframe && uiDialog.bgiframe());
		(options.autoOpen && this.open());
	},
	
	setData: function(key, value){
		(setDataSwitch[key] && this.uiDialog.data(setDataSwitch[key], value));
		switch (key) {
			case "buttons":
				this.createButtons(value);
				break;
			case "draggable":
				this.uiDialog.draggable(value ? 'enable' : 'disable');
				break;
			case "height":
				this.uiDialog.height(value);
				break;
			case "position":
				this.position(value);
				break;
			case "resizable":
				(typeof value == 'string' && this.uiDialog.data('handles.resizable', value));
				this.uiDialog.resizable(value ? 'enable' : 'disable');
				break;
			case "title":
				$(".ui-dialog-title", this.uiDialogTitlebar).html(value || '&nbsp;');
				break;
			case "width":
				this.uiDialog.width(value);
				break;
		}
		
		$.widget.prototype.setData.apply(this, arguments);
	},
	
	position: function(pos) {
		var wnd = $(window), doc = $(document),
			pTop = doc.scrollTop(), pLeft = doc.scrollLeft(),
			minTop = pTop;
		
		if ($.inArray(pos, ['center','top','right','bottom','left']) >= 0) {
			pos = [
				pos == 'right' || pos == 'left' ? pos : 'center',
				pos == 'top' || pos == 'bottom' ? pos : 'middle'
			];
		}
		if (pos.constructor != Array) {
			pos = ['center', 'middle'];
		}
		if (pos[0].constructor == Number) {
			pLeft += pos[0];
		} else {
			switch (pos[0]) {
				case 'left':
					pLeft += 0;
					break;
				case 'right':
					pLeft += wnd.width() - this.uiDialog.width();
					break;
				default:
				case 'center':
					pLeft += (wnd.width() - this.uiDialog.width()) / 2;
			}
		}
		if (pos[1].constructor == Number) {
			pTop += pos[1];
		} else {
			switch (pos[1]) {
				case 'top':
					pTop += 0;
					break;
				case 'bottom':
					pTop += wnd.height() - this.uiDialog.height();
					break;
				default:
				case 'middle':
					pTop += (wnd.height() - this.uiDialog.height()) / 2;
			}
		}
		
		// prevent the dialog from being too high (make sure the titlebar
		// is accessible)
		pTop = Math.max(pTop, minTop);
		this.uiDialog.css({top: pTop, left: pLeft});
	},
	
	size: function() {
		var container = this.uiDialogContainer,
			titlebar = this.uiDialogTitlebar,
			content = this.element,
			tbMargin = (parseInt(content.css('margin-top'), 10) || 0)
				+ (parseInt(content.css('margin-bottom'), 10) || 0),
			lrMargin = (parseInt(content.css('margin-left'), 10) || 0)
				+ (parseInt(content.css('margin-right'), 10) || 0);
		content.height(container.height() - titlebar.outerHeight() - tbMargin);
		content.width(container.width() - lrMargin);
	},
	
	open: function() {
		if (this.isOpen) { return; }
		
		this.overlay = this.options.modal ? new $.ui.dialog.overlay(this) : null;
		(this.uiDialog.next().length && this.uiDialog.appendTo('body'));
		this.position(this.options.position);
		this.uiDialog.show(this.options.show);
		(this.options.autoResize && this.size());
		this.moveToTop(true);
		
		this.trigger('open', null, { options: this.options });
		this.isOpen = true;
	},
	
	// the force parameter allows us to move modal dialogs to their correct
	// position on open
	moveToTop: function(force) {
		
		if ((this.options.modal && !force)
			|| (!this.options.stack && !this.options.modal)) {
			return this.trigger('focus', null, { options: this.options });
		}
		
		var maxZ = this.options.zIndex, options = this.options;
		$('.ui-dialog:visible').each(function() {
			maxZ = Math.max(maxZ, parseInt($(this).css('z-index'), 10) || options.zIndex);
		});
		(this.overlay && this.overlay.$el.css('z-index', ++maxZ));
		this.uiDialog.css('z-index', ++maxZ);
		
		this.trigger('focus', null, { options: this.options });
	},
	
	close: function() {
		(this.overlay && this.overlay.destroy());
		this.uiDialog.hide(this.options.hide);
		
		this.trigger('close', null, { options: this.options });
		$.ui.dialog.overlay.resize();
		
		this.isOpen = false;
	},
	
	destroy: function() {
		(this.overlay && this.overlay.destroy());
		this.uiDialog.hide();
		this.element
			.unbind('.dialog')
			.removeData('dialog')
			.removeClass('ui-dialog-content')
			.hide().appendTo('body');
		this.uiDialog.remove();
	},
	
	createButtons: function(buttons) {
		var self = this,
			hasButtons = false,
			uiDialogButtonPane = this.uiDialogButtonPane;
		
		// remove any existing buttons
		uiDialogButtonPane.empty().hide();
		
		$.each(buttons, function() { return !(hasButtons = true); });
		if (hasButtons) {
			uiDialogButtonPane.show();
			$.each(buttons, function(name, fn) {
				$('<button/>')
					.text(name)
					.click(function() { fn.apply(self.element[0], arguments); })
					.appendTo(uiDialogButtonPane);
			});
		}
	},
	
	fakeEvent: function(type) {
		return $.event.fix({
			type: type,
			target: this.element[0]
		});
	}
});

$.extend($.ui.dialog, {
	defaults: {
		autoOpen: true,
		autoResize: true,
		bgiframe: false,
		buttons: {},
		closeOnEscape: true,
		draggable: true,
		height: 200,
		minHeight: 100,
		minWidth: 150,
		modal: false,
		overlay: {},
		position: 'center',
		resizable: true,
		stack: true,
		width: 300,
		zIndex: 1000
	},
	
	overlay: function(dialog) {
		this.$el = $.ui.dialog.overlay.create(dialog);
	}
});

$.extend($.ui.dialog.overlay, {
	instances: [],
	events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','),
		function(e) { return e + '.dialog-overlay'; }).join(' '),
	create: function(dialog) {
		if (this.instances.length === 0) {
			// prevent use of anchors and inputs
			// we use a setTimeout in case the overlay is created from an
			// event that we're going to be cancelling (see #2804)
			setTimeout(function() {
				$('a, :input').bind($.ui.dialog.overlay.events, function() {
					// allow use of the element if inside a dialog and
					// - there are no modal dialogs
					// - there are modal dialogs, but we are in front of the topmost modal
					var allow = false;
					var $dialog = $(this).parents('.ui-dialog');
					if ($dialog.length) {
						var $overlays = $('.ui-dialog-overlay');
						if ($overlays.length) {
							var maxZ = parseInt($overlays.css('z-index'), 10);
							$overlays.each(function() {
								maxZ = Math.max(maxZ, parseInt($(this).css('z-index'), 10));
							});
							allow = parseInt($dialog.css('z-index'), 10) > maxZ;
						} else {
							allow = true;
						}
					}
					return allow;
				});
			}, 1);
			
			// allow closing by pressing the escape key
			$(document).bind('keydown.dialog-overlay', function(e) {
				var ESC = 27;
				(e.keyCode && e.keyCode == ESC && dialog.close()); 
			});
			
			// handle window resize
			$(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize);
		}
		
		var $el = $('<div/>').appendTo(document.body)
			.addClass('ui-dialog-overlay').css($.extend({
				borderWidth: 0, margin: 0, padding: 0,
				position: 'absolute', top: 0, left: 0,
				width: this.width(),
				height: this.height()
			}, dialog.options.overlay));
		
		(dialog.options.bgiframe && $.fn.bgiframe && $el.bgiframe());
		
		this.instances.push($el);
		return $el;
	},
	
	destroy: function($el) {
		this.instances.splice($.inArray(this.instances, $el), 1);
		
		if (this.instances.length === 0) {
			$('a, :input').add([document, window]).unbind('.dialog-overlay');
		}
		
		$el.remove();
	},
	
	height: function() {
		// handle IE 6
		if ($.browser.msie && $.browser.version < 7) {
			var scrollHeight = Math.max(
				document.documentElement.scrollHeight,
				document.body.scrollHeight
			);
			var offsetHeight = Math.max(
				document.documentElement.offsetHeight,
				document.body.offsetHeight
			);
			
			if (scrollHeight < offsetHeight) {
				return $(window).height() + 'px';
			} else {
				return scrollHeight + 'px';
			}
		// handle Opera
		} else if ($.browser.opera) {
			return Math.max(
				window.innerHeight,
				$(document).height()
			) + 'px';
		// handle "good" browsers
		} else {
			return $(document).height() + 'px';
		}
	},
	
	width: function() {
		// handle IE 6
		if ($.browser.msie && $.browser.version < 7) {
			var scrollWidth = Math.max(
				document.documentElement.scrollWidth,
				document.body.scrollWidth
			);
			var offsetWidth = Math.max(
				document.documentElement.offsetWidth,
				document.body.offsetWidth
			);
			
			if (scrollWidth < offsetWidth) {
				return $(window).width() + 'px';
			} else {
				return scrollWidth + 'px';
			}
		// handle Opera
		} else if ($.browser.opera) {
			return Math.max(
				window.innerWidth,
				$(document).width()
			) + 'px';
		// handle "good" browsers
		} else {
			return $(document).width() + 'px';
		}
	},
	
	resize: function() {
		/* If the dialog is draggable and the user drags it past the
		 * right edge of the window, the document becomes wider so we
		 * need to stretch the overlay. If the user then drags the
		 * dialog back to the left, the document will become narrower,
		 * so we need to shrink the overlay to the appropriate size.
		 * This is handled by shrinking the overlay before setting it
		 * to the full document size.
		 */
		var $overlays = $([]);
		$.each($.ui.dialog.overlay.instances, function() {
			$overlays = $overlays.add(this);
		});
		
		$overlays.css({
			width: 0,
			height: 0
		}).css({
			width: $.ui.dialog.overlay.width(),
			height: $.ui.dialog.overlay.height()
		});
	}
});

$.extend($.ui.dialog.overlay.prototype, {
	destroy: function() {
		$.ui.dialog.overlay.destroy(this.$el);
	}
});

})(jQuery);

/*
 * jQuery UI Datepicker
 *
 * Copyright (c) 2006, 2007, 2008 Marc Grabanski
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 * 
 * http://docs.jquery.com/UI/Datepicker
 *
 * Depends:
 *	ui.core.js
 *
 * Marc Grabanski (m@marcgrabanski.com) and Keith Wood (kbwood@virginbroadband.com.au).
 */
   
(function($) { // hide the namespace

var PROP_NAME = 'datepicker';

/* Date picker manager.
   Use the singleton instance of this class, $.datepicker, to interact with the date picker.
   Settings for (groups of) date pickers are maintained in an instance object,
   allowing multiple different settings on the same page. */

function Datepicker() {
	this.debug = false; // Change this to true to start debugging
	this._curInst = null; // The current instance in use
	this._disabledInputs = []; // List of date picker inputs that have been disabled
	this._datepickerShowing = false; // True if the popup picker is showing , false if not
	this._inDialog = false; // True if showing within a "dialog", false if not
	this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division
	this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class
	this._appendClass = 'ui-datepicker-append'; // The name of the append marker class
	this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class
	this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class
	this._promptClass = 'ui-datepicker-prompt'; // The name of the dialog prompt marker class
	this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class
	this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class
	this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class
	this.regional = []; // Available regional settings, indexed by language code
	this.regional[''] = { // Default regional settings
		clearText: 'Clear', // Display text for clear link
		clearStatus: 'Erase the current date', // Status text for clear link
		closeText: 'Close', // Display text for close link
		closeStatus: 'Close without change', // Status text for close link
		prevText: '&#x3c;Prev', // Display text for previous month link
		prevStatus: 'Show the previous month', // Status text for previous month link
		prevBigText: '&#x3c;&#x3c;', // Display text for previous year link
		prevBigStatus: 'Show the previous year', // Status text for previous year link
		nextText: 'Next&#x3e;', // Display text for next month link
		nextStatus: 'Show the next month', // Status text for next month link
		nextBigText: '&#x3e;&#x3e;', // Display text for next year link
		nextBigStatus: 'Show the next year', // Status text for next year link
		currentText: 'Today', // Display text for current month link
		currentStatus: 'Show the current month', // Status text for current month link
		monthNames: ['January','February','March','April','May','June',
			'July','August','September','October','November','December'], // Names of months for drop-down and formatting
		monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
		monthStatus: 'Show a different month', // Status text for selecting a month
		yearStatus: 'Show a different year', // Status text for selecting a year
		weekHeader: 'Wk', // Header for the week of the year column
		weekStatus: 'Week of the year', // Status text for the week of the year column
		dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
		dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting
		dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday
		dayStatus: 'Set DD as first week day', // Status text for the day of the week selection
		dateStatus: 'Select DD, M d', // Status text for the date selection
		dateFormat: 'mm/dd/yy', // See format options on parseDate
		firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
		initStatus: 'Select a date', // Initial Status text on opening
		isRTL: false // True if right-to-left language, false if left-to-right
	};
	this._defaults = { // Global defaults for all the date picker instances
		showOn: 'focus', // 'focus' for popup on focus,
			// 'button' for trigger button, or 'both' for either
		showAnim: 'show', // Name of jQuery animation for popup
		showOptions: {}, // Options for enhanced animations
		defaultDate: null, // Used when field is blank: actual date,
			// +/-number for offset from today, null for today
		appendText: '', // Display text following the input box, e.g. showing the format
		buttonText: '...', // Text for trigger button
		buttonImage: '', // URL for trigger button image
		buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
		closeAtTop: true, // True to have the clear/close at the top,
			// false to have them at the bottom
		mandatory: false, // True to hide the Clear link, false to include it
		hideIfNoPrevNext: false, // True to hide next/previous month links
			// if not applicable, false to just disable them
		navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
		showBigPrevNext: false, // True to show big prev/next links
		gotoCurrent: false, // True if today link goes back to current selection instead
		changeMonth: true, // True if month can be selected directly, false if only prev/next
		changeYear: true, // True if year can be selected directly, false if only prev/next
		showMonthAfterYear: false, // True if the year select precedes month, false for month then year
		yearRange: '-10:+10', // Range of years to display in drop-down,
			// either relative to current year (-nn:+nn) or absolute (nnnn:nnnn)
		changeFirstDay: true, // True to click on day name to change, false to remain as set
		highlightWeek: false, // True to highlight the selected week
		showOtherMonths: false, // True to show dates in other months, false to leave blank
		showWeeks: false, // True to show week of the year, false to omit
		calculateWeek: this.iso8601Week, // How to calculate the week of the year,
			// takes a Date and returns the number of the week for it
		shortYearCutoff: '+10', // Short year values < this are in the current century,
			// > this are in the previous century, 
			// string value starting with '+' for current year + value
		showStatus: false, // True to show status bar at bottom, false to not show it
		statusForDate: this.dateStatus, // Function to provide status text for a date -
			// takes date and instance as parameters, returns display text
		minDate: null, // The earliest selectable date, or null for no limit
		maxDate: null, // The latest selectable date, or null for no limit
		duration: 'normal', // Duration of display/closure
		beforeShowDay: null, // Function that takes a date and returns an array with
			// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '', 
			// [2] = cell title (optional), e.g. $.datepicker.noWeekends
		beforeShow: null, // Function that takes an input field and
			// returns a set of custom settings for the date picker
		onSelect: null, // Define a callback function when a date is selected
		onChangeMonthYear: null, // Define a callback function when the month or year is changed
		onClose: null, // Define a callback function when the datepicker is closed
		numberOfMonths: 1, // Number of months to show at a time
		showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
		stepMonths: 1, // Number of months to step back/forward
		stepBigMonths: 12, // Number of months to step back/forward for the big links
		rangeSelect: false, // Allows for selecting a date range on one date picker
		rangeSeparator: ' - ', // Text between two dates in a range
		altField: '', // Selector for an alternate field to store selected dates into
		altFormat: '' // The date format to use for the alternate field
	};
	$.extend(this._defaults, this.regional['']);
	this.dpDiv = $('<div id="' + this._mainDivId + '" style="display: none;"></div>');
}

$.extend(Datepicker.prototype, {
	/* Class name added to elements to indicate already configured with a date picker. */
	markerClassName: 'hasDatepicker',

	/* Debug logging (if enabled). */
	log: function () {
		if (this.debug)
			console.log.apply('', arguments);
	},
	
	/* Override the default settings for all instances of the date picker. 
	   @param  settings  object - the new settings to use as defaults (anonymous object)
	   @return the manager object */
	setDefaults: function(settings) {
		extendRemove(this._defaults, settings || {});
		return this;
	},

	/* Attach the date picker to a jQuery selection.
	   @param  target    element - the target input field or division or span
	   @param  settings  object - the new settings to use for this date picker instance (anonymous) */
	_attachDatepicker: function(target, settings) {
		// check for settings on the control itself - in namespace 'date:'
		var inlineSettings = null;
		for (attrName in this._defaults) {
			var attrValue = target.getAttribute('date:' + attrName);
			if (attrValue) {
				inlineSettings = inlineSettings || {};
				try {
					inlineSettings[attrName] = eval(attrValue);
				} catch (err) {
					inlineSettings[attrName] = attrValue;
				}
			}
		}
		var nodeName = target.nodeName.toLowerCase();
		var inline = (nodeName == 'div' || nodeName == 'span');
		if (!target.id)
			target.id = 'dp' + new Date().getTime();
		var inst = this._newInst($(target), inline);
		inst.settings = $.extend({}, settings || {}, inlineSettings || {}); 
		if (nodeName == 'input') {
			this._connectDatepicker(target, inst);
		} else if (inline) {
			this._inlineDatepicker(target, inst);
		}
	},

	/* Create a new instance object. */
	_newInst: function(target, inline) {
		var id = target[0].id.replace(/([:\[\]\.])/g, '\\\\$1'); // escape jQuery meta chars
		return {id: id, input: target, // associated target
			selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
			drawMonth: 0, drawYear: 0, // month being drawn
			inline: inline, // is datepicker inline or not
			dpDiv: (!inline ? this.dpDiv : // presentation div
			$('<div class="' + this._inlineClass + '"></div>'))};
	},

	/* Attach the date picker to an input field. */
	_connectDatepicker: function(target, inst) {
		var input = $(target);
		if (input.hasClass(this.markerClassName))
			return;
		var appendText = this._get(inst, 'appendText');
		var isRTL = this._get(inst, 'isRTL');
		if (appendText)
			input[isRTL ? 'before' : 'after']('<span class="' + this._appendClass + '">' + appendText + '</span>');
		var showOn = this._get(inst, 'showOn');
		if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field
			input.focus(this._showDatepicker);
		if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked
			var buttonText = this._get(inst, 'buttonText');
			var buttonImage = this._get(inst, 'buttonImage');
			var trigger = $(this._get(inst, 'buttonImageOnly') ? 
				$('<img/>').addClass(this._triggerClass).
					attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
				$('<button type="button"></button>').addClass(this._triggerClass).
					html(buttonImage == '' ? buttonText : $('<img/>').attr(
					{ src:buttonImage, alt:buttonText, title:buttonText })));
			input[isRTL ? 'before' : 'after'](trigger);
			trigger.click(function() {
				if ($.datepicker._datepickerShowing && $.datepicker._lastInput == target)
					$.datepicker._hideDatepicker();
				else
					$.datepicker._showDatepicker(target);
				return false;
			});
		}
		input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).
			bind("setData.datepicker", function(event, key, value) {
				inst.settings[key] = value;
			}).bind("getData.datepicker", function(event, key) {
				return this._get(inst, key);
			});
		$.data(target, PROP_NAME, inst);
	},

	/* Attach an inline date picker to a div. */
	_inlineDatepicker: function(target, inst) {
		var input = $(target);
		if (input.hasClass(this.markerClassName))
			return;
		input.addClass(this.markerClassName).append(inst.dpDiv).
			bind("setData.datepicker", function(event, key, value){
				inst.settings[key] = value;
			}).bind("getData.datepicker", function(event, key){
				return this._get(inst, key);
			});
		$.data(target, PROP_NAME, inst);
		this._setDate(inst, this._getDefaultDate(inst));
		this._updateDatepicker(inst);
	},

	/* Tidy up after displaying the date picker. */
	_inlineShow: function(inst) {
		var numMonths = this._getNumberOfMonths(inst); // fix width for dynamic number of date pickers
		inst.dpDiv.width(numMonths[1] * $('.ui-datepicker', inst.dpDiv[0]).width());
	}, 

	/* Pop-up the date picker in a "dialog" box.
	   @param  input     element - ignored
	   @param  dateText  string - the initial date to display (in the current format)
	   @param  onSelect  function - the function(dateText) to call when a date is selected
	   @param  settings  object - update the dialog date picker instance's settings (anonymous object)
	   @param  pos       int[2] - coordinates for the dialog's position within the screen or
	                     event - with x/y coordinates or
	                     leave empty for default (screen centre)
	   @return the manager object */
	_dialogDatepicker: function(input, dateText, onSelect, settings, pos) {
		var inst = this._dialogInst; // internal instance
		if (!inst) {
			var id = 'dp' + new Date().getTime();
			this._dialogInput = $('<input type="text" id="' + id +
				'" size="1" style="position: absolute; top: -100px;"/>');
			this._dialogInput.keydown(this._doKeyDown);
			$('body').append(this._dialogInput);
			inst = this._dialogInst = this._newInst(this._dialogInput, false);
			inst.settings = {};
			$.data(this._dialogInput[0], PROP_NAME, inst);
		}
		extendRemove(inst.settings, settings || {});
		this._dialogInput.val(dateText);

		this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
		if (!this._pos) {
			var browserWidth = window.innerWidth || document.documentElement.clientWidth ||	document.body.clientWidth;
			var browserHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
			var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
			var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
			this._pos = // should use actual width/height below
				[(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
		}

		// move input on screen for focus, but hidden behind dialog
		this._dialogInput.css('left', this._pos[0] + 'px').css('top', this._pos[1] + 'px');
		inst.settings.onSelect = onSelect;
		this._inDialog = true;
		this.dpDiv.addClass(this._dialogClass);
		this._showDatepicker(this._dialogInput[0]);
		if ($.blockUI)
			$.blockUI(this.dpDiv);
		$.data(this._dialogInput[0], PROP_NAME, inst);
		return this;
	},

	/* Detach a datepicker from its control.
	   @param  target    element - the target input field or division or span */
	_destroyDatepicker: function(target) {
		var $target = $(target);
		if (!$target.hasClass(this.markerClassName)) {
			return;
		}
		var nodeName = target.nodeName.toLowerCase();
		$.removeData(target, PROP_NAME);
		if (nodeName == 'input') {
			$target.siblings('.' + this._appendClass).remove().end().
				siblings('.' + this._triggerClass).remove().end().
				removeClass(this.markerClassName).
				unbind('focus', this._showDatepicker).
				unbind('keydown', this._doKeyDown).
				unbind('keypress', this._doKeyPress);
		} else if (nodeName == 'div' || nodeName == 'span')
			$target.removeClass(this.markerClassName).empty();
	},

	/* Enable the date picker to a jQuery selection.
	   @param  target    element - the target input field or division or span */
	_enableDatepicker: function(target) {
		var $target = $(target);
		if (!$target.hasClass(this.markerClassName)) {
			return;
		}
		var nodeName = target.nodeName.toLowerCase();
		if (nodeName == 'input') {
		target.disabled = false;
			$target.siblings('button.' + this._triggerClass).
			each(function() { this.disabled = false; }).end().
				siblings('img.' + this._triggerClass).
				css({opacity: '1.0', cursor: ''});
		}
		else if (nodeName == 'div' || nodeName == 'span') {
			$target.children('.' + this._disableClass).remove();
		}
		this._disabledInputs = $.map(this._disabledInputs,
			function(value) { return (value == target ? null : value); }); // delete entry
	},

	/* Disable the date picker to a jQuery selection.
	   @param  target    element - the target input field or division or span */
	_disableDatepicker: function(target) {
		var $target = $(target);
		if (!$target.hasClass(this.markerClassName)) {
			return;
		}
		var nodeName = target.nodeName.toLowerCase();
		if (nodeName == 'input') {
		target.disabled = true;
			$target.siblings('button.' + this._triggerClass).
			each(function() { this.disabled = true; }).end().
				siblings('img.' + this._triggerClass).
				css({opacity: '0.5', cursor: 'default'});
		}
		else if (nodeName == 'div' || nodeName == 'span') {
			var inline = $target.children('.' + this._inlineClass);
			var offset = inline.offset();
			var relOffset = {left: 0, top: 0};
			inline.parents().each(function() {
				if ($(this).css('position') == 'relative') {
					relOffset = $(this).offset();
					return false;
				}
			});
			$target.prepend('<div class="' + this._disableClass + '" style="' +
				($.browser.msie ? 'background-color: transparent; ' : '') +
				'width: ' + inline.width() + 'px; height: ' + inline.height() +
				'px; left: ' + (offset.left - relOffset.left) +
				'px; top: ' + (offset.top - relOffset.top) + 'px;"></div>');
		}
		this._disabledInputs = $.map(this._disabledInputs,
			function(value) { return (value == target ? null : value); }); // delete entry
		this._disabledInputs[this._disabledInputs.length] = target;
	},

	/* Is the first field in a jQuery collection disabled as a datepicker?
	   @param  target    element - the target input field or division or span
	   @return boolean - true if disabled, false if enabled */
	_isDisabledDatepicker: function(target) {
		if (!target)
			return false;
		for (var i = 0; i < this._disabledInputs.length; i++) {
			if (this._disabledInputs[i] == target)
				return true;
		}
		return false;
	},

	/* Update the settings for a date picker attached to an input field or division.
	   @param  target  element - the target input field or division or span
	   @param  name    object - the new settings to update or
	                   string - the name of the setting to change or
	   @param  value   any - the new value for the setting (omit if above is an object) */
	_changeDatepicker: function(target, name, value) {
		var settings = name || {};
		if (typeof name == 'string') {
			settings = {};
			settings[name] = value;
		}
		var inst = $.data(target, PROP_NAME);
		if (inst) {
			if (this._curInst == inst) {
				this._hideDatepicker(null);
			}
			extendRemove(inst.settings, settings);
			var date = new Date();
			extendRemove(inst, {rangeStart: null, // start of range
				endDay: null, endMonth: null, endYear: null, // end of range
				selectedDay: date.getDate(), selectedMonth: date.getMonth(),
				selectedYear: date.getFullYear(), // starting point
				currentDay: date.getDate(), currentMonth: date.getMonth(),
				currentYear: date.getFullYear(), // current selection
				drawMonth: date.getMonth(), drawYear: date.getFullYear()}); // month being drawn
			this._updateDatepicker(inst);
		}
	},

	/* Set the dates for a jQuery selection.
	   @param  target   element - the target input field or division or span
	   @param  date     Date - the new date
	   @param  endDate  Date - the new end date for a range (optional) */
	_setDateDatepicker: function(target, date, endDate) {
		var inst = $.data(target, PROP_NAME);
		if (inst) {
			this._setDate(inst, date, endDate);
			this._updateDatepicker(inst);
		}
	},

	/* Get the date(s) for the first entry in a jQuery selection.
	   @param  target  element - the target input field or division or span
	   @return Date - the current date or
	           Date[2] - the current dates for a range */
	_getDateDatepicker: function(target) {
		var inst = $.data(target, PROP_NAME);
		if (inst && !inst.inline)
			this._setDateFromField(inst); 
		return (inst ? this._getDate(inst) : null);
	},

	/* Handle keystrokes. */
	_doKeyDown: function(e) {
		var inst = $.data(e.target, PROP_NAME);
		var handled = true;
		if ($.datepicker._datepickerShowing)
			switch (e.keyCode) {
				case 9:  $.datepicker._hideDatepicker(null, '');
						break; // hide on tab out
				case 13: $.datepicker._selectDay(e.target, inst.selectedMonth, inst.selectedYear,
							$('td.ui-datepicker-days-cell-over', inst.dpDiv)[0]);
						return false; // don't submit the form
						break; // select the value on enter
				case 27: $.datepicker._hideDatepicker(null, $.datepicker._get(inst, 'duration'));
						break; // hide on escape
				case 33: $.datepicker._adjustDate(e.target, (e.ctrlKey ?
							-$.datepicker._get(inst, 'stepBigMonths') :
							-$.datepicker._get(inst, 'stepMonths')), 'M');
						break; // previous month/year on page up/+ ctrl
				case 34: $.datepicker._adjustDate(e.target, (e.ctrlKey ?
							+$.datepicker._get(inst, 'stepBigMonths') :
							+$.datepicker._get(inst, 'stepMonths')), 'M');
						break; // next month/year on page down/+ ctrl
				case 35: if (e.ctrlKey) $.datepicker._clearDate(e.target);
						handled = e.ctrlKey;
						break; // clear on ctrl+end
				case 36: if (e.ctrlKey) $.datepicker._gotoToday(e.target);
						handled = e.ctrlKey;
						break; // current on ctrl+home
				case 37: if (e.ctrlKey) $.datepicker._adjustDate(e.target, -1, 'D');
						handled = e.ctrlKey;
						break; // -1 day on ctrl+left
				case 38: if (e.ctrlKey) $.datepicker._adjustDate(e.target, -7, 'D');
						handled = e.ctrlKey;
						break; // -1 week on ctrl+up
				case 39: if (e.ctrlKey) $.datepicker._adjustDate(e.target, +1, 'D');
						handled = e.ctrlKey;
						break; // +1 day on ctrl+right
				case 40: if (e.ctrlKey) $.datepicker._adjustDate(e.target, +7, 'D');
						handled = e.ctrlKey;
						break; // +1 week on ctrl+down
				default: handled = false;
			}
		else if (e.keyCode == 36 && e.ctrlKey) // display the date picker on ctrl+home
			$.datepicker._showDatepicker(this);
		else
			handled = false;
		if (handled) {
			e.preventDefault();
			e.stopPropagation();
		}
	},

	/* Filter entered characters - based on date format. */
	_doKeyPress: function(e) {
		var inst = $.data(e.target, PROP_NAME);
		var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat'));
		var chr = String.fromCharCode(e.charCode == undefined ? e.keyCode : e.charCode);
		return e.ctrlKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
	},

	/* Pop-up the date picker for a given input field.
	   @param  input  element - the input field attached to the date picker or
	                  event - if triggered by focus */
	_showDatepicker: function(input) {
		input = input.target || input;
		if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger
			input = $('input', input.parentNode)[0];
		if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here
			return;
		var inst = $.data(input, PROP_NAME);
		var beforeShow = $.datepicker._get(inst, 'beforeShow');
		extendRemove(inst.settings, (beforeShow ? beforeShow.apply(input, [input, inst]) : {}));
		$.datepicker._hideDatepicker(null, '');
		$.datepicker._lastInput = input;
		$.datepicker._setDateFromField(inst);
		if ($.datepicker._inDialog) // hide cursor
			input.value = '';
		if (!$.datepicker._pos) { // position below input
			$.datepicker._pos = $.datepicker._findPos(input);
			$.datepicker._pos[1] += input.offsetHeight; // add the height
		}
		var isFixed = false;
		$(input).parents().each(function() {
			isFixed |= $(this).css('position') == 'fixed';
			return !isFixed;
		});
		if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled
			$.datepicker._pos[0] -= document.documentElement.scrollLeft;
			$.datepicker._pos[1] -= document.documentElement.scrollTop;
		}
		var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
		$.datepicker._pos = null;
		inst.rangeStart = null;
		// determine sizing offscreen
		inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'});
		$.datepicker._updateDatepicker(inst);
		// fix width for dynamic number of date pickers
		inst.dpDiv.width($.datepicker._getNumberOfMonths(inst)[1] *
			$('.ui-datepicker', inst.dpDiv[0])[0].offsetWidth);
		// and adjust position before showing
		offset = $.datepicker._checkOffset(inst, offset, isFixed);
		inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
			'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
			left: offset.left + 'px', top: offset.top + 'px'});
		if (!inst.inline) {
			var showAnim = $.datepicker._get(inst, 'showAnim') || 'show';
			var duration = $.datepicker._get(inst, 'duration');
			var postProcess = function() {
				$.datepicker._datepickerShowing = true;
				if ($.browser.msie && parseInt($.browser.version) < 7) // fix IE < 7 select problems
					$('iframe.ui-datepicker-cover').css({width: inst.dpDiv.width() + 4,
						height: inst.dpDiv.height() + 4});
			};
			if ($.effects && $.effects[showAnim])
				inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
			else
				inst.dpDiv[showAnim](duration, postProcess);
			if (duration == '')
				postProcess();
			if (inst.input[0].type != 'hidden')
				inst.input[0].focus();
			$.datepicker._curInst = inst;
		}
	},

	/* Generate the date picker content. */
	_updateDatepicker: function(inst) {
		var dims = {width: inst.dpDiv.width() + 4,
			height: inst.dpDiv.height() + 4};
		inst.dpDiv.empty().append(this._generateHTML(inst)).
			find('iframe.ui-datepicker-cover').
			css({width: dims.width, height: dims.height});
		var numMonths = this._getNumberOfMonths(inst);
		inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') +
			'Class']('ui-datepicker-multi');
		inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') +
			'Class']('ui-datepicker-rtl');
		if (inst.input && inst.input[0].type != 'hidden')
			$(inst.input[0]).focus();
	},

	/* Check positioning to remain on screen. */
	_checkOffset: function(inst, offset, isFixed) {
		var pos = inst.input ? this._findPos(inst.input[0]) : null;
		var browserWidth = window.innerWidth || document.documentElement.clientWidth;
		var browserHeight = window.innerHeight || document.documentElement.clientHeight;
		var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
		var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
		// reposition date picker horizontally if outside the browser window
		if (this._get(inst, 'isRTL') || (offset.left + inst.dpDiv.width() - scrollX) > browserWidth)
			offset.left = Math.max((isFixed ? 0 : scrollX),
				pos[0] + (inst.input ? inst.input.width() : 0) - (isFixed ? scrollX : 0) - inst.dpDiv.width() -
				(isFixed && $.browser.opera ? document.documentElement.scrollLeft : 0));
		else
			offset.left -= (isFixed ? scrollX : 0);
		// reposition date picker vertically if outside the browser window
		if ((offset.top + inst.dpDiv.height() - scrollY) > browserHeight)
			offset.top = Math.max((isFixed ? 0 : scrollY),
				pos[1] - (isFixed ? scrollY : 0) - (this._inDialog ? 0 : inst.dpDiv.height()) -
				(isFixed && $.browser.opera ? document.documentElement.scrollTop : 0));
		else
			offset.top -= (isFixed ? scrollY : 0);
		return offset;
	},
	
	/* Find an object's position on the screen. */
	_findPos: function(obj) {
        while (obj && (obj.type == 'hidden' || obj.nodeType != 1)) {
            obj = obj.nextSibling;
        }
        var position = $(obj).offset();
	    return [position.left, position.top];
	},

	/* Hide the date picker from view.
	   @param  input  element - the input field attached to the date picker
	   @param  duration  string - the duration over which to close the date picker */
	_hideDatepicker: function(input, duration) {
		var inst = this._curInst;
		if (!inst || (input && inst != $.data(input, PROP_NAME)))
			return;
		var rangeSelect = this._get(inst, 'rangeSelect');
		if (rangeSelect && inst.stayOpen)
			this._selectDate('#' + inst.id, this._formatDate(inst,
				inst.currentDay, inst.currentMonth, inst.currentYear));
		inst.stayOpen = false;
		if (this._datepickerShowing) {
			duration = (duration != null ? duration : this._get(inst, 'duration'));
			var showAnim = this._get(inst, 'showAnim');
			var postProcess = function() {
				$.datepicker._tidyDialog(inst);
			};
			if (duration != '' && $.effects && $.effects[showAnim])
				inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'),
					duration, postProcess);
			else
				inst.dpDiv[(duration == '' ? 'hide' : (showAnim == 'slideDown' ? 'slideUp' :
					(showAnim == 'fadeIn' ? 'fadeOut' : 'hide')))](duration, postProcess);
			if (duration == '')
				this._tidyDialog(inst);
			var onClose = this._get(inst, 'onClose');
			if (onClose)
				onClose.apply((inst.input ? inst.input[0] : null),
					[this._getDate(inst), inst]);  // trigger custom callback
			this._datepickerShowing = false;
			this._lastInput = null;
			inst.settings.prompt = null;
			if (this._inDialog) {
				this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
				if ($.blockUI) {
					$.unblockUI();
					$('body').append(this.dpDiv);
				}
			}
			this._inDialog = false;
		}
		this._curInst = null;
	},

	/* Tidy up after a dialog display. */
	_tidyDialog: function(inst) {
		inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker');
		$('.' + this._promptClass, inst.dpDiv).remove();
	},

	/* Close date picker if clicked elsewhere. */
	_checkExternalClick: function(event) {
		if (!$.datepicker._curInst)
			return;
		var $target = $(event.target);
		if (($target.parents('#' + $.datepicker._mainDivId).length == 0) &&
				!$target.hasClass($.datepicker.markerClassName) &&
				!$target.hasClass($.datepicker._triggerClass) &&
				$.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI))
			$.datepicker._hideDatepicker(null, '');
	},

	/* Adjust one of the date sub-fields. */
	_adjustDate: function(id, offset, period) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		this._adjustInstDate(inst, offset, period);
		this._updateDatepicker(inst);
	},

	/* Action for current link. */
	_gotoToday: function(id) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		if (this._get(inst, 'gotoCurrent') && inst.currentDay) {
			inst.selectedDay = inst.currentDay;
			inst.drawMonth = inst.selectedMonth = inst.currentMonth;
			inst.drawYear = inst.selectedYear = inst.currentYear;
		}
		else {
		var date = new Date();
		inst.selectedDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = date.getFullYear();
		}
		this._notifyChange(inst);
		this._adjustDate(target);
	},

	/* Action for selecting a new month/year. */
	_selectMonthYear: function(id, select, period) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		inst._selectingMonthYear = false;
		inst['selected' + (period == 'M' ? 'Month' : 'Year')] =
		inst['draw' + (period == 'M' ? 'Month' : 'Year')] =
			parseInt(select.options[select.selectedIndex].value);
		this._notifyChange(inst);
		this._adjustDate(target);
	},

	/* Restore input focus after not changing month/year. */
	_clickMonthYear: function(id) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		if (inst.input && inst._selectingMonthYear && !$.browser.msie)
			inst.input[0].focus();
		inst._selectingMonthYear = !inst._selectingMonthYear;
	},

	/* Action for changing the first week day. */
	_changeFirstDay: function(id, day) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		inst.settings.firstDay = day;
		this._updateDatepicker(inst);
	},

	/* Action for selecting a day. */
	_selectDay: function(id, month, year, td) {
		if ($(td).hasClass(this._unselectableClass))
			return;
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		var rangeSelect = this._get(inst, 'rangeSelect');
		if (rangeSelect) {
			inst.stayOpen = !inst.stayOpen;
			if (inst.stayOpen) {
				$('.ui-datepicker td', inst.dpDiv).removeClass(this._currentClass);
				$(td).addClass(this._currentClass);
			} 
		}
		inst.selectedDay = inst.currentDay = $('a', td).html();
		inst.selectedMonth = inst.currentMonth = month;
		inst.selectedYear = inst.currentYear = year;
		if (inst.stayOpen) {
			inst.endDay = inst.endMonth = inst.endYear = null;
		}
		else if (rangeSelect) {
			inst.endDay = inst.currentDay;
			inst.endMonth = inst.currentMonth;
			inst.endYear = inst.currentYear;
		}
		this._selectDate(id, this._formatDate(inst,
			inst.currentDay, inst.currentMonth, inst.currentYear));
		if (inst.stayOpen) {
			inst.rangeStart = new Date(inst.currentYear, inst.currentMonth, inst.currentDay);
			this._updateDatepicker(inst);
		}
		else if (rangeSelect) {
			inst.selectedDay = inst.currentDay = inst.rangeStart.getDate();
			inst.selectedMonth = inst.currentMonth = inst.rangeStart.getMonth();
			inst.selectedYear = inst.currentYear = inst.rangeStart.getFullYear();
			inst.rangeStart = null;
			if (inst.inline)
				this._updateDatepicker(inst);
		}
	},

	/* Erase the input field and hide the date picker. */
	_clearDate: function(id) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		if (this._get(inst, 'mandatory'))
			return;
		inst.stayOpen = false;
		inst.endDay = inst.endMonth = inst.endYear = inst.rangeStart = null;
		this._selectDate(target, '');
	},

	/* Update the input field with the selected date. */
	_selectDate: function(id, dateStr) {
		var target = $(id);
		var inst = $.data(target[0], PROP_NAME);
		dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
		if (this._get(inst, 'rangeSelect') && dateStr)
			dateStr = (inst.rangeStart ? this._formatDate(inst, inst.rangeStart) :
				dateStr) + this._get(inst, 'rangeSeparator') + dateStr;
		if (inst.input)
			inst.input.val(dateStr);
		this._updateAlternate(inst);
		var onSelect = this._get(inst, 'onSelect');
		if (onSelect)
			onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);  // trigger custom callback
		else if (inst.input)
			inst.input.trigger('change'); // fire the change event
		if (inst.inline)
			this._updateDatepicker(inst);
		else if (!inst.stayOpen) {
			this._hideDatepicker(null, this._get(inst, 'duration'));
			this._lastInput = inst.input[0];
			if (typeof(inst.input[0]) != 'object')
				inst.input[0].focus(); // restore focus
			this._lastInput = null;
		}
	},
	
	/* Update any alternate field to synchronise with the main field. */
	_updateAlternate: function(inst) {
		var altField = this._get(inst, 'altField');
		if (altField) { // update alternate field too
			var altFormat = this._get(inst, 'altFormat');
			var date = this._getDate(inst);
			dateStr = (isArray(date) ? (!date[0] && !date[1] ? '' :
				this.formatDate(altFormat, date[0], this._getFormatConfig(inst)) +
				this._get(inst, 'rangeSeparator') + this.formatDate(
				altFormat, date[1] || date[0], this._getFormatConfig(inst))) :
				this.formatDate(altFormat, date, this._getFormatConfig(inst)));
			$(altField).each(function() { $(this).val(dateStr); });
		}
	},

	/* Set as beforeShowDay function to prevent selection of weekends.
	   @param  date  Date - the date to customise
	   @return [boolean, string] - is this date selectable?, what is its CSS class? */
	noWeekends: function(date) {
		var day = date.getDay();
		return [(day > 0 && day < 6), ''];
	},
	
	/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
	   @param  date  Date - the date to get the week for
	   @return  number - the number of the week within the year that contains this date */
	iso8601Week: function(date) {
		var checkDate = new Date(date.getFullYear(), date.getMonth(), date.getDate(), (date.getTimezoneOffset() / -60));
		var firstMon = new Date(checkDate.getFullYear(), 1 - 1, 4); // First week always contains 4 Jan
		var firstDay = firstMon.getDay() || 7; // Day of week: Mon = 1, ..., Sun = 7
		firstMon.setDate(firstMon.getDate() + 1 - firstDay); // Preceding Monday
		if (firstDay < 4 && checkDate < firstMon) { // Adjust first three days in year if necessary
			checkDate.setDate(checkDate.getDate() - 3); // Generate for previous year
			return $.datepicker.iso8601Week(checkDate);
		} else if (checkDate > new Date(checkDate.getFullYear(), 12 - 1, 28)) { // Check last three days in year
			firstDay = new Date(checkDate.getFullYear() + 1, 1 - 1, 4).getDay() || 7;
			if (firstDay > 4 && (checkDate.getDay() || 7) < firstDay - 3) { // Adjust if necessary
				checkDate.setDate(checkDate.getDate() + 3); // Generate for next year
				return $.datepicker.iso8601Week(checkDate);
			}
		}
		return Math.floor(((checkDate - firstMon) / 86400000) / 7) + 1; // Weeks to given date
	},
	
	/* Provide status text for a particular date.
	   @param  date  the date to get the status for
	   @param  inst  the current datepicker instance
	   @return  the status display text for this date */
	dateStatus: function(date, inst) {
		return $.datepicker.formatDate($.datepicker._get(inst, 'dateStatus'),
			date, $.datepicker._getFormatConfig(inst));
	},

	/* Parse a string value into a date object.
	   See formatDate below for the possible formats.

	   @param  format    string - the expected format of the date
	   @param  value     string - the date in the above format
	   @param  settings  Object - attributes include:
	                     shortYearCutoff  number - the cutoff year for determining the century (optional)
	                     dayNamesShort    string[7] - abbreviated names of the days from Sunday (optional)
	                     dayNames         string[7] - names of the days from Sunday (optional)
	                     monthNamesShort  string[12] - abbreviated names of the months (optional)
	                     monthNames       string[12] - names of the months (optional)
	   @return  Date - the extracted date value or null if value is blank */
	parseDate: function (format, value, settings) {
		if (format == null || value == null)
			throw 'Invalid arguments';
		value = (typeof value == 'object' ? value.toString() : value + '');
		if (value == '')
			return null;
		var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff;
		var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
		var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
		var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
		var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
		var year = -1;
		var month = -1;
		var day = -1;
		var doy = -1;
		var literal = false;
		// Check whether a format character is doubled
		var lookAhead = function(match) {
			var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
			if (matches)
				iFormat++;
			return matches;	
		};
		// Extract a number from the string value
		var getNumber = function(match) {
			lookAhead(match);
			var origSize = (match == '@' ? 14 : (match == 'y' ? 4 : (match == 'o' ? 3 : 2)));
			var size = origSize;
			var num = 0;
			while (size > 0 && iValue < value.length &&
					value.charAt(iValue) >= '0' && value.charAt(iValue) <= '9') {
				num = num * 10 + parseInt(value.charAt(iValue++));
				size--;
			}
			if (size == origSize)
				throw 'Missing number at position ' + iValue;
			return num;
		};
		// Extract a name from the string value and convert to an index
		var getName = function(match, shortNames, longNames) {
			var names = (lookAhead(match) ? longNames : shortNames);
			var size = 0;
			for (var j = 0; j < names.length; j++)
				size = Math.max(size, names[j].length);
			var name = '';
			var iInit = iValue;
			while (size > 0 && iValue < value.length) {
				name += value.charAt(iValue++);
				for (var i = 0; i < names.length; i++)
					if (name == names[i])
						return i + 1;
				size--;
			}
			throw 'Unknown name at position ' + iInit;
		};
		// Confirm that a literal character matches the string value
		var checkLiteral = function() {
			if (value.charAt(iValue) != format.charAt(iFormat))
				throw 'Unexpected literal at position ' + iValue;
			iValue++;
		};
		var iValue = 0;
		for (var iFormat = 0; iFormat < format.length; iFormat++) {
			if (literal)
				if (format.charAt(iFormat) == "'" && !lookAhead("'"))
					literal = false;
				else
					checkLiteral();
			else
				switch (format.charAt(iFormat)) {
					case 'd':
						day = getNumber('d');
						break;
					case 'D': 
						getName('D', dayNamesShort, dayNames);
						break;
					case 'o':
						doy = getNumber('o');
						break;
					case 'm': 
						month = getNumber('m');
						break;
					case 'M':
						month = getName('M', monthNamesShort, monthNames); 
						break;
					case 'y':
						year = getNumber('y');
						break;
					case '@':
						var date = new Date(getNumber('@'));
						year = date.getFullYear();
						month = date.getMonth() + 1;
						day = date.getDate();
						break;
					case "'":
						if (lookAhead("'"))
							checkLiteral();
						else
							literal = true;
						break;
					default:
						checkLiteral();
				}
		}
		if (year < 100)
			year += new Date().getFullYear() - new Date().getFullYear() % 100 +
				(year <= shortYearCutoff ? 0 : -100);
		if (doy > -1) {
			month = 1;
			day = doy;
			do {
				var dim = this._getDaysInMonth(year, month - 1);
				if (day <= dim)
					break;
				month++;
				day -= dim;
			} while (true);
		}
		var date = new Date(year, month - 1, day);
		if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day)
			throw 'Invalid date'; // E.g. 31/02/*
		return date;
	},

	/* Standard date formats. */
	ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601)
	COOKIE: 'D, dd M yy',
	ISO_8601: 'yy-mm-dd',
	RFC_822: 'D, d M y',
	RFC_850: 'DD, dd-M-y',
	RFC_1036: 'D, d M y',
	RFC_1123: 'D, d M yy',
	RFC_2822: 'D, d M yy',
	RSS: 'D, d M y', // RFC 822
	TIMESTAMP: '@',
	W3C: 'yy-mm-dd', // ISO 8601

	/* Format a date object into a string value.
	   The format can be combinations of the following:
	   d  - day of month (no leading zero)
	   dd - day of month (two digit)
	   o  - day of year (no leading zeros)
	   oo - day of year (three digit)
	   D  - day name short
	   DD - day name long
	   m  - month of year (no leading zero)
	   mm - month of year (two digit)
	   M  - month name short
	   MM - month name long
	   y  - year (two digit)
	   yy - year (four digit)
	   @ - Unix timestamp (ms since 01/01/1970)
	   '...' - literal text
	   '' - single quote

	   @param  format    string - the desired format of the date
	   @param  date      Date - the date value to format
	   @param  settings  Object - attributes include:
	                     dayNamesShort    string[7] - abbreviated names of the days from Sunday (optional)
	                     dayNames         string[7] - names of the days from Sunday (optional)
	                     monthNamesShort  string[12] - abbreviated names of the months (optional)
	                     monthNames       string[12] - names of the months (optional)
	   @return  string - the date in the above format */
	formatDate: function (format, date, settings) {
		if (!date)
			return '';
		var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
		var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
		var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
		var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
		// Check whether a format character is doubled
		var lookAhead = function(match) {
			var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
			if (matches)
				iFormat++;
			return matches;	
		};
		// Format a number, with leading zero if necessary
		var formatNumber = function(match, value, len) {
			var num = '' + value;
			if (lookAhead(match))
				while (num.length < len)
					num = '0' + num;
			return num;
		};
		// Format a name, short or long as requested
		var formatName = function(match, value, shortNames, longNames) {
			return (lookAhead(match) ? longNames[value] : shortNames[value]);
		};
		var output = '';
		var literal = false;
		if (date)
			for (var iFormat = 0; iFormat < format.length; iFormat++) {
				if (literal)
					if (format.charAt(iFormat) == "'" && !lookAhead("'"))
						literal = false;
					else
						output += format.charAt(iFormat);
				else
					switch (format.charAt(iFormat)) {
						case 'd':
							output += formatNumber('d', date.getDate(), 2);
							break;
						case 'D': 
							output += formatName('D', date.getDay(), dayNamesShort, dayNames);
							break;
						case 'o':
							var doy = date.getDate();
							for (var m = date.getMonth() - 1; m >= 0; m--)
								doy += this._getDaysInMonth(date.getFullYear(), m);
							output += formatNumber('o', doy, 3);
							break;
						case 'm': 
							output += formatNumber('m', date.getMonth() + 1, 2);
							break;
						case 'M':
							output += formatName('M', date.getMonth(), monthNamesShort, monthNames); 
							break;
						case 'y':
							output += (lookAhead('y') ? date.getFullYear() : 
								(date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100);
							break;
						case '@':
							output += date.getTime(); 
							break;
						case "'":
							if (lookAhead("'"))
								output += "'";
							else
								literal = true;
							break;
						default:
							output += format.charAt(iFormat);
					}
			}
		return output;
	},

	/* Extract all possible characters from the date format. */
	_possibleChars: function (format) {
		var chars = '';
		var literal = false;
		for (var iFormat = 0; iFormat < format.length; iFormat++)
			if (literal)
				if (format.charAt(iFormat) == "'" && !lookAhead("'"))
					literal = false;
				else
					chars += format.charAt(iFormat);
			else
				switch (format.charAt(iFormat)) {
					case 'd': case 'm': case 'y': case '@':
						chars += '0123456789'; 
						break;
					case 'D': case 'M':
						return null; // Accept anything
					case "'":
						if (lookAhead("'"))
							chars += "'";
						else
							literal = true;
						break;
					default:
						chars += format.charAt(iFormat);
				}
		return chars;
	},

	/* Get a setting value, defaulting if necessary. */
	_get: function(inst, name) {
		return inst.settings[name] !== undefined ?
			inst.settings[name] : this._defaults[name];
	},

	/* Parse existing date and initialise date picker. */
	_setDateFromField: function(inst) {
		var dateFormat = this._get(inst, 'dateFormat');
		var dates = inst.input ? inst.input.val().split(this._get(inst, 'rangeSeparator')) : null; 
		inst.endDay = inst.endMonth = inst.endYear = null;
		var date = defaultDate = this._getDefaultDate(inst);
		if (dates.length > 0) {
			var settings = this._getFormatConfig(inst);
			if (dates.length > 1) {
				date = this.parseDate(dateFormat, dates[1], settings) || defaultDate;
				inst.endDay = date.getDate();
				inst.endMonth = date.getMonth();
				inst.endYear = date.getFullYear();
			}
			try {
				date = this.parseDate(dateFormat, dates[0], settings) || defaultDate;
			} catch (e) {
				this.log(e);
				date = defaultDate;
			}
		}
		inst.selectedDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = date.getFullYear();
		inst.currentDay = (dates[0] ? date.getDate() : 0);
		inst.currentMonth = (dates[0] ? date.getMonth() : 0);
		inst.currentYear = (dates[0] ? date.getFullYear() : 0);
		this._adjustInstDate(inst);
	},
	
	/* Retrieve the default date shown on opening. */
	_getDefaultDate: function(inst) {
		var date = this._determineDate(this._get(inst, 'defaultDate'), new Date());
		var minDate = this._getMinMaxDate(inst, 'min', true);
		var maxDate = this._getMinMaxDate(inst, 'max');
		date = (minDate && date < minDate ? minDate : date);
		date = (maxDate && date > maxDate ? maxDate : date);
		return date;
	},

	/* A date may be specified as an exact value or a relative one. */
	_determineDate: function(date, defaultDate) {
		var offsetNumeric = function(offset) {
			var date = new Date();
			date.setUTCDate(date.getUTCDate() + offset);
			return date;
		};
		var offsetString = function(offset, getDaysInMonth) {
			var date = new Date();
			var year = date.getFullYear();
			var month = date.getMonth();
			var day = date.getDate();
			var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;
			var matches = pattern.exec(offset);
			while (matches) {
				switch (matches[2] || 'd') {
					case 'd' : case 'D' :
						day += parseInt(matches[1]); break;
					case 'w' : case 'W' :
						day += parseInt(matches[1]) * 7; break;
					case 'm' : case 'M' :
						month += parseInt(matches[1]); 
						day = Math.min(day, getDaysInMonth(year, month));
						break;
					case 'y': case 'Y' :
						year += parseInt(matches[1]);
						day = Math.min(day, getDaysInMonth(year, month));
						break;
				}
				matches = pattern.exec(offset);
			}
			return new Date(year, month, day);
		};
		return (date == null ? defaultDate :
			(typeof date == 'string' ? offsetString(date, this._getDaysInMonth) :
			(typeof date == 'number' ? offsetNumeric(date) : date)));
	},

	/* Set the date(s) directly. */
	_setDate: function(inst, date, endDate) {
		var clear = !(date);
		var origMonth = inst.selectedMonth;
		var origYear = inst.selectedYear;
		date = this._determineDate(date, new Date());
		inst.selectedDay = inst.currentDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = inst.currentMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = inst.currentYear = date.getFullYear();
		if (this._get(inst, 'rangeSelect')) {
			if (endDate) {
				endDate = this._determineDate(endDate, null);
				inst.endDay = endDate.getDate();
				inst.endMonth = endDate.getMonth();
				inst.endYear = endDate.getFullYear();
			} else {
				inst.endDay = inst.currentDay;
				inst.endMonth = inst.currentMonth;
				inst.endYear = inst.currentYear;
			}
		}
		if (origMonth != inst.selectedMonth || origYear != inst.selectedYear)
			this._notifyChange(inst);
		this._adjustInstDate(inst);
		if (inst.input)
			inst.input.val(clear ? '' : this._formatDate(inst) +
				(!this._get(inst, 'rangeSelect') ? '' : this._get(inst, 'rangeSeparator') +
				this._formatDate(inst, inst.endDay, inst.endMonth, inst.endYear)));
	},

	/* Retrieve the date(s) directly. */
	_getDate: function(inst) {
		var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null :
			new Date(inst.currentYear, inst.currentMonth, inst.currentDay));
		if (this._get(inst, 'rangeSelect')) {
			return [inst.rangeStart || startDate,
				(!inst.endYear ? inst.rangeStart || startDate :
				new Date(inst.endYear, inst.endMonth, inst.endDay))];
		} else
			return startDate;
	},

	/* Generate the HTML for the current state of the date picker. */
	_generateHTML: function(inst) {
		var today = new Date();
		today = new Date(today.getFullYear(), today.getMonth(), today.getDate()); // clear time
		var showStatus = this._get(inst, 'showStatus');
		var initStatus = this._get(inst, 'initStatus') || '&#xa0;';
		var isRTL = this._get(inst, 'isRTL');
		// build the date picker HTML
		var clear = (this._get(inst, 'mandatory') ? '' :
			'<div class="ui-datepicker-clear"><a onclick="jQuery.datepicker._clearDate(\'#' + inst.id + '\');"' +
			this._addStatus(showStatus, inst.id, this._get(inst, 'clearStatus'), initStatus) + '>' +
			this._get(inst, 'clearText') + '</a></div>');
		var controls = '<div class="ui-datepicker-control">' + (isRTL ? '' : clear) +
			'<div class="ui-datepicker-close"><a onclick="jQuery.datepicker._hideDatepicker();"' +
			this._addStatus(showStatus, inst.id, this._get(inst, 'closeStatus'), initStatus) + '>' +
			this._get(inst, 'closeText') + '</a></div>' + (isRTL ? clear : '')  + '</div>';
		var prompt = this._get(inst, 'prompt');
		var closeAtTop = this._get(inst, 'closeAtTop');
		var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext');
		var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat');
		var showBigPrevNext = this._get(inst, 'showBigPrevNext');
		var numMonths = this._getNumberOfMonths(inst);
		var showCurrentAtPos = this._get(inst, 'showCurrentAtPos');
		var stepMonths = this._get(inst, 'stepMonths');
		var stepBigMonths = this._get(inst, 'stepBigMonths');
		var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1);
		var currentDate = (!inst.currentDay ? new Date(9999, 9, 9) :
			new Date(inst.currentYear, inst.currentMonth, inst.currentDay));
		var minDate = this._getMinMaxDate(inst, 'min', true);
		var maxDate = this._getMinMaxDate(inst, 'max');
		var drawMonth = inst.drawMonth - showCurrentAtPos;
		var drawYear = inst.drawYear;
		if (drawMonth < 0) {
			drawMonth += 12;
			drawYear--;
		}
		if (maxDate) {
			var maxDraw = new Date(maxDate.getFullYear(),
				maxDate.getMonth() - numMonths[1] + 1, maxDate.getDate());
			maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
			while (new Date(drawYear, drawMonth, 1) > maxDraw) {
				drawMonth--;
				if (drawMonth < 0) {
					drawMonth = 11;
					drawYear--;
				}
			}
		}
		// controls and links
		var prevText = this._get(inst, 'prevText');
		prevText = (!navigationAsDateFormat ? prevText : this.formatDate(
			prevText, new Date(drawYear, drawMonth - stepMonths, 1), this._getFormatConfig(inst)));
		var prevBigText = (showBigPrevNext ? this._get(inst, 'prevBigText') : '');
		prevBigText = (!navigationAsDateFormat ? prevBigText : this.formatDate(
			prevBigText, new Date(drawYear, drawMonth - stepBigMonths, 1), this._getFormatConfig(inst)));
		var prev = '<div class="ui-datepicker-prev">' + (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? 
			(showBigPrevNext ? '<a onclick="jQuery.datepicker._adjustDate(\'#' + inst.id + '\', -' + stepBigMonths + ', \'M\');"' +
			this._addStatus(showStatus, inst.id, this._get(inst, 'prevBigStatus'), initStatus) + '>' + prevBigText + '</a>' : '') +
			'<a onclick="jQuery.datepicker._adjustDate(\'#' + inst.id + '\', -' + stepMonths + ', \'M\');"' +
			this._addStatus(showStatus, inst.id, this._get(inst, 'prevStatus'), initStatus) + '>' + prevText + '</a>' :
			(hideIfNoPrevNext ? '' : '<label>' + prevBigText + '</label><label>' + prevText + '</label>')) + '</div>';
		var nextText = this._get(inst, 'nextText');
		nextText = (!navigationAsDateFormat ? nextText : this.formatDate(
			nextText, new Date(drawYear, drawMonth + stepMonths, 1), this._getFormatConfig(inst)));
		var nextBigText = (showBigPrevNext ? this._get(inst, 'nextBigText') : '');
		nextBigText = (!navigationAsDateFormat ? nextBigText : this.formatDate(
			nextBigText, new Date(drawYear, drawMonth + stepBigMonths, 1), this._getFormatConfig(inst)));
		var next = '<div class="ui-datepicker-next">' + (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
			'<a onclick="jQuery.datepicker._adjustDate(\'#' + inst.id + '\', +' + stepMonths + ', \'M\');"' +
			this._addStatus(showStatus, inst.id, this._get(inst, 'nextStatus'), initStatus) + '>' + nextText + '</a>' +
			(showBigPrevNext ? '<a onclick="jQuery.datepicker._adjustDate(\'#' + inst.id + '\', +' + stepBigMonths + ', \'M\');"' +
			this._addStatus(showStatus, inst.id, this._get(inst, 'nextBigStatus'), initStatus) + '>' + nextBigText + '</a>' : '') :
			(hideIfNoPrevNext ? '' : '<label>' + nextText + '</label><label>' + nextBigText + '</label>')) + '</div>';
		var currentText = this._get(inst, 'currentText');
		var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today); 
		currentText = (!navigationAsDateFormat ? currentText :
			this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
		var html = (prompt ? '<div class="' + this._promptClass + '">' + prompt + '</div>' : '') +
			(closeAtTop && !inst.inline ? controls : '') +
			'<div class="ui-datepicker-links">' + (isRTL ? next : prev) +
			(this._isInRange(inst, gotoDate) ? '<div class="ui-datepicker-current">' +
			'<a onclick="jQuery.datepicker._gotoToday(\'#' + inst.id + '\');"' +
			this._addStatus(showStatus, inst.id, this._get(inst, 'currentStatus'), initStatus) + '>' +
			currentText + '</a></div>' : '') + (isRTL ? prev : next) + '</div>';
		var firstDay = this._get(inst, 'firstDay');
		var changeFirstDay = this._get(inst, 'changeFirstDay');
		var dayNames = this._get(inst, 'dayNames');
		var dayNamesShort = this._get(inst, 'dayNamesShort');
		var dayNamesMin = this._get(inst, 'dayNamesMin');
		var monthNames = this._get(inst, 'monthNames');
		var beforeShowDay = this._get(inst, 'beforeShowDay');
		var highlightWeek = this._get(inst, 'highlightWeek');
		var showOtherMonths = this._get(inst, 'showOtherMonths');
		var showWeeks = this._get(inst, 'showWeeks');
		var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;
		var weekStatus = this._get(inst, 'weekStatus');
		var status = (showStatus ? this._get(inst, 'dayStatus') || initStatus : '');
		var dateStatus = this._get(inst, 'statusForDate') || this.dateStatus;
		var endDate = inst.endDay ? new Date(inst.endYear, inst.endMonth, inst.endDay) : currentDate;
		for (var row = 0; row < numMonths[0]; row++)
			for (var col = 0; col < numMonths[1]; col++) {
				var selectedDate = new Date(drawYear, drawMonth, inst.selectedDay);
				html += '<div class="ui-datepicker-one-month' + (col == 0 ? ' ui-datepicker-new-row' : '') + '">' +
					this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
					selectedDate, row > 0 || col > 0, showStatus, initStatus, monthNames) + // draw month headers
					'<table class="ui-datepicker" cellpadding="0" cellspacing="0"><thead>' + 
					'<tr class="ui-datepicker-title-row">' +
					(showWeeks ? '<td' + this._addStatus(showStatus, inst.id, weekStatus, initStatus) + '>' +
					this._get(inst, 'weekHeader') + '</td>' : '');
				for (var dow = 0; dow < 7; dow++) { // days of the week
					var day = (dow + firstDay) % 7;
					var dayStatus = (status.indexOf('DD') > -1 ? status.replace(/DD/, dayNames[day]) :
						status.replace(/D/, dayNamesShort[day]));
					html += '<td' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="ui-datepicker-week-end-cell"' : '') + '>' +
						(!changeFirstDay ? '<span' :
						'<a onclick="jQuery.datepicker._changeFirstDay(\'#' + inst.id + '\', ' + day + ');"') + 
						this._addStatus(showStatus, inst.id, dayStatus, initStatus) + ' title="' + dayNames[day] + '">' +
						dayNamesMin[day] + (changeFirstDay ? '</a>' : '</span>') + '</td>';
				}
				html += '</tr></thead><tbody>';
				var daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
				if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth)
					inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
				var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
				var tzDate = new Date(drawYear, drawMonth, 1 - leadDays);
				var utcDate = new Date(drawYear, drawMonth, 1 - leadDays);
				var printDate = utcDate;
				var numRows = (isMultiMonth ? 6 : Math.ceil((leadDays + daysInMonth) / 7)); // calculate the number of rows to generate
				for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows
					html += '<tr class="ui-datepicker-days-row">' +
						(showWeeks ? '<td class="ui-datepicker-week-col"' +
						this._addStatus(showStatus, inst.id, weekStatus, initStatus) + '>' +
						calculateWeek(printDate) + '</td>' : '');
					for (var dow = 0; dow < 7; dow++) { // create date picker days
						var daySettings = (beforeShowDay ?
							beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']);
						var otherMonth = (printDate.getMonth() != drawMonth);
						var unselectable = otherMonth || !daySettings[0] ||
							(minDate && printDate < minDate) || (maxDate && printDate > maxDate);
						html += '<td class="ui-datepicker-days-cell' +
							((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end-cell' : '') + // highlight weekends
							(otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months
							(printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth ?
							' ui-datepicker-days-cell-over' : '') + // highlight selected day
							(unselectable ? ' ' + this._unselectableClass : '') +  // highlight unselectable days
							(otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates
							(printDate.getTime() >= currentDate.getTime() && printDate.getTime() <= endDate.getTime() ?  // in current range
							' ' + this._currentClass : '') + // highlight selected day
							(printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '"' + // highlight today (if different)
							((!otherMonth || showOtherMonths) && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // cell title
							(unselectable ? (highlightWeek ? ' onmouseover="jQuery(this).parent().addClass(\'ui-datepicker-week-over\');"' + // highlight selection week
							' onmouseout="jQuery(this).parent().removeClass(\'ui-datepicker-week-over\');"' : '') : // unhighlight selection week
							' onmouseover="jQuery(this).addClass(\'ui-datepicker-days-cell-over\')' + // highlight selection
							(highlightWeek ? '.parent().addClass(\'ui-datepicker-week-over\')' : '') + ';' + // highlight selection week
							(!showStatus || (otherMonth && !showOtherMonths) ? '' : 'jQuery(\'#ui-datepicker-status-' +
							inst.id + '\').html(\'' + (dateStatus.apply((inst.input ? inst.input[0] : null),
							[printDate, inst]) || initStatus) +'\');') + '"' +
							' onmouseout="jQuery(this).removeClass(\'ui-datepicker-days-cell-over\')' + // unhighlight selection
							(highlightWeek ? '.parent().removeClass(\'ui-datepicker-week-over\')' : '') + ';' + // unhighlight selection week
							(!showStatus || (otherMonth && !showOtherMonths) ? '' : 'jQuery(\'#ui-datepicker-status-' +
							inst.id + '\').html(\'' + initStatus + '\');') + '" onclick="jQuery.datepicker._selectDay(\'#' +
							inst.id + '\',' + drawMonth + ',' + drawYear + ', this);"') + '>' + // actions
							(otherMonth ? (showOtherMonths ? printDate.getDate() : '&#xa0;') : // display for other months
							(unselectable ? printDate.getDate() : '<a>' + printDate.getDate() + '</a>')) + '</td>'; // display for this month
						tzDate.setDate(tzDate.getDate() + 1);
						utcDate.setUTCDate(utcDate.getUTCDate() + 1);
						printDate = (tzDate > utcDate ? tzDate : utcDate);
					}
					html += '</tr>';
				}
				drawMonth++;
				if (drawMonth > 11) {
					drawMonth = 0;
					drawYear++;
				}
				html += '</tbody></table></div>';
			}
		html += (showStatus ? '<div style="clear: both;"></div><div id="ui-datepicker-status-' + inst.id + 
			'" class="ui-datepicker-status">' + initStatus + '</div>' : '') +
			(!closeAtTop && !inst.inline ? controls : '') +
			'<div style="clear: both;"></div>' + 
			($.browser.msie && parseInt($.browser.version) < 7 && !inst.inline ? 
			'<iframe src="javascript:false;" class="ui-datepicker-cover"></iframe>' : '');
		return html;
	},
	
	/* Generate the month and year header. */
	_generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
			selectedDate, secondary, showStatus, initStatus, monthNames) {
		minDate = (inst.rangeStart && minDate && selectedDate < minDate ? selectedDate : minDate);
		var showMonthAfterYear = this._get(inst, 'showMonthAfterYear');
		var html = '<div class="ui-datepicker-header">';
		var monthHtml = '';
		// month selection
		if (secondary || !this._get(inst, 'changeMonth'))
			monthHtml += monthNames[drawMonth] + '&#xa0;';
		else {
			var inMinYear = (minDate && minDate.getFullYear() == drawYear);
			var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear);
			monthHtml += '<select class="ui-datepicker-new-month" ' +
				'onchange="jQuery.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'M\');" ' +
				'onclick="jQuery.datepicker._clickMonthYear(\'#' + inst.id + '\');"' +
				this._addStatus(showStatus, inst.id, this._get(inst, 'monthStatus'), initStatus) + '>';
			for (var month = 0; month < 12; month++) {
				if ((!inMinYear || month >= minDate.getMonth()) &&
						(!inMaxYear || month <= maxDate.getMonth()))
					monthHtml += '<option value="' + month + '"' +
						(month == drawMonth ? ' selected="selected"' : '') +
						'>' + monthNames[month] + '</option>';
			}
			monthHtml += '</select>';
		}
		if (!showMonthAfterYear)
			html += monthHtml;
		// year selection
		if (secondary || !this._get(inst, 'changeYear'))
			html += drawYear;
		else {
			// determine range of years to display
			var years = this._get(inst, 'yearRange').split(':');
			var year = 0;
			var endYear = 0;
			if (years.length != 2) {
				year = drawYear - 10;
				endYear = drawYear + 10;
			} else if (years[0].charAt(0) == '+' || years[0].charAt(0) == '-') {
				year = endYear = new Date().getFullYear();
				year += parseInt(years[0], 10);
				endYear += parseInt(years[1], 10);
			} else {
				year = parseInt(years[0], 10);
				endYear = parseInt(years[1], 10);
			}
			year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
			endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
			html += '<select class="ui-datepicker-new-year" ' +
				'onchange="jQuery.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'Y\');" ' +
				'onclick="jQuery.datepicker._clickMonthYear(\'#' + inst.id + '\');"' +
				this._addStatus(showStatus, inst.id, this._get(inst, 'yearStatus'), initStatus) + '>';
			for (; year <= endYear; year++) {
				html += '<option value="' + year + '"' +
					(year == drawYear ? ' selected="selected"' : '') +
					'>' + year + '</option>';
			}
			html += '</select>';
		}
		if (showMonthAfterYear)
			html += monthHtml;
		html += '</div>'; // Close datepicker_header
		return html;
	},

	/* Provide code to set and clear the status panel. */
	_addStatus: function(showStatus, id, text, initStatus) {
		return (showStatus ? ' onmouseover="jQuery(\'#ui-datepicker-status-' + id +
			'\').html(\'' + (text || initStatus) + '\');" ' +
			'onmouseout="jQuery(\'#ui-datepicker-status-' + id +
			'\').html(\'' + initStatus + '\');"' : '');
	},

	/* Adjust one of the date sub-fields. */
	_adjustInstDate: function(inst, offset, period) {
		var year = inst.drawYear + (period == 'Y' ? offset : 0);
		var month = inst.drawMonth + (period == 'M' ? offset : 0);
		var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) +
			(period == 'D' ? offset : 0);
		var date = new Date(year, month, day);
		// ensure it is within the bounds set
		var minDate = this._getMinMaxDate(inst, 'min', true);
		var maxDate = this._getMinMaxDate(inst, 'max');
		date = (minDate && date < minDate ? minDate : date);
		date = (maxDate && date > maxDate ? maxDate : date);
		inst.selectedDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = date.getFullYear();
		if (period == 'M' || period == 'Y')
			this._notifyChange(inst);
	},

	/* Notify change of month/year. */
	_notifyChange: function(inst) {
		var onChange = this._get(inst, 'onChangeMonthYear');
		if (onChange)
			onChange.apply((inst.input ? inst.input[0] : null),
				[new Date(inst.selectedYear, inst.selectedMonth, 1), inst]);
	},
	
	/* Determine the number of months to show. */
	_getNumberOfMonths: function(inst) {
		var numMonths = this._get(inst, 'numberOfMonths');
		return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths));
	},

	/* Determine the current maximum date - ensure no time components are set - may be overridden for a range. */
	_getMinMaxDate: function(inst, minMax, checkRange) {
		var date = this._determineDate(this._get(inst, minMax + 'Date'), null);
		if (date) {
			date.setHours(0);
			date.setMinutes(0);
			date.setSeconds(0);
			date.setMilliseconds(0);
		}
		return (!checkRange || !inst.rangeStart ? date :
			(!date || inst.rangeStart > date ? inst.rangeStart : date));
	},

	/* Find the number of days in a given month. */
	_getDaysInMonth: function(year, month) {
		return 32 - new Date(year, month, 32).getDate();
	},

	/* Find the day of the week of the first of a month. */
	_getFirstDayOfMonth: function(year, month) {
		return new Date(year, month, 1).getDay();
	},

	/* Determines if we should allow a "next/prev" month display change. */
	_canAdjustMonth: function(inst, offset, curYear, curMonth) {
		var numMonths = this._getNumberOfMonths(inst);
		var date = new Date(curYear, curMonth + (offset < 0 ? offset : numMonths[1]), 1);
		if (offset < 0)
			date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
		return this._isInRange(inst, date);
	},

	/* Is the given date in the accepted range? */
	_isInRange: function(inst, date) {
		// during range selection, use minimum of selected date and range start
		var newMinDate = (!inst.rangeStart ? null :
			new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay));
		newMinDate = (newMinDate && inst.rangeStart < newMinDate ? inst.rangeStart : newMinDate);
		var minDate = newMinDate || this._getMinMaxDate(inst, 'min');
		var maxDate = this._getMinMaxDate(inst, 'max');
		return ((!minDate || date >= minDate) && (!maxDate || date <= maxDate));
	},
	
	/* Provide the configuration settings for formatting/parsing. */
	_getFormatConfig: function(inst) {
		var shortYearCutoff = this._get(inst, 'shortYearCutoff');
		shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
			new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
		return {shortYearCutoff: shortYearCutoff,
			dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'),
			monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')};
	},

	/* Format the given date for display. */
	_formatDate: function(inst, day, month, year) {
		if (!day) {
			inst.currentDay = inst.selectedDay;
			inst.currentMonth = inst.selectedMonth;
			inst.currentYear = inst.selectedYear;
		}
		var date = (day ? (typeof day == 'object' ? day : new Date(year, month, day)) :
			new Date(inst.currentYear, inst.currentMonth, inst.currentDay));
		return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst));
	}
});

/* jQuery extend now ignores nulls! */
function extendRemove(target, props) {
	$.extend(target, props);
	for (var name in props)
		if (props[name] == null || props[name] == undefined)
			target[name] = props[name];
	return target;
};

/* Determine whether an object is an array. */
function isArray(a) {
	return (a && (($.browser.safari && typeof a == 'object' && a.length) ||
		(a.constructor && a.constructor.toString().match(/\Array\(\)/))));
};

/* Invoke the datepicker functionality.
   @param  options  string - a command, optionally followed by additional parameters or
                    Object - settings for attaching new datepicker functionality
   @return  jQuery object */
$.fn.datepicker = function(options){
	
	/* Initialise the date picker. */
	if (!$.datepicker.initialized) {
		$(document.body).append($.datepicker.dpDiv).
			mousedown($.datepicker._checkExternalClick);
		$.datepicker.initialized = true;
	}
	
	var otherArgs = Array.prototype.slice.call(arguments, 1);
	if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate'))
		return $.datepicker['_' + options + 'Datepicker'].
			apply($.datepicker, [this[0]].concat(otherArgs));
	return this.each(function() {
		typeof options == 'string' ?
			$.datepicker['_' + options + 'Datepicker'].
				apply($.datepicker, [this].concat(otherArgs)) :
			$.datepicker._attachDatepicker(this, options);
	});
};

$.datepicker = new Datepicker(); // singleton instance
$.datepicker.initialized = false;

})(jQuery);

/*
 * jQuery UI Tabs
 *
 * Copyright (c) 2007, 2008 Klaus Hartl (stilbuero.de)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://docs.jquery.com/UI/Tabs
 *
 * Depends:
 *	ui.core.js
 */
(function($) {

$.widget("ui.tabs", {
	init: function() {
		this.options.event += '.tabs'; // namespace event
		
		// create tabs
		this.tabify(true);
	},
	setData: function(key, value) {
		if ((/^selected/).test(key))
			this.select(value);
		else {
			this.options[key] = value;
			this.tabify();
		}
	},
	length: function() {
		return this.$tabs.length;
	},
	tabId: function(a) {
		return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '')
			|| this.options.idPrefix + $.data(a);
	},
	ui: function(tab, panel) {
		return {
			options: this.options,
			tab: tab,
			panel: panel,
			index: this.$tabs.index(tab)
		};
	},
	tabify: function(init) {

		this.$lis = $('li:has(a[href])', this.element);
		this.$tabs = this.$lis.map(function() { return $('a', this)[0]; });
		this.$panels = $([]);

		var self = this, o = this.options;

		this.$tabs.each(function(i, a) {
			// inline tab
			if (a.hash && a.hash.replace('#', '')) // Safari 2 reports '#' for an empty hash
				self.$panels = self.$panels.add(a.hash);
			// remote tab
			else if ($(a).attr('href') != '#') { // prevent loading the page itself if href is just "#"
				$.data(a, 'href.tabs', a.href); // required for restore on destroy
				$.data(a, 'load.tabs', a.href); // mutable
				var id = self.tabId(a);
				a.href = '#' + id;
				var $panel = $('#' + id);
				if (!$panel.length) {
					$panel = $(o.panelTemplate).attr('id', id).addClass(o.panelClass)
						.insertAfter( self.$panels[i - 1] || self.element );
					$panel.data('destroy.tabs', true);
				}
				self.$panels = self.$panels.add( $panel );
			}
			// invalid tab href
			else
				o.disabled.push(i + 1);
		});

		if (init) {

			// attach necessary classes for styling if not present
			this.element.addClass(o.navClass);
			this.$panels.each(function() {
				var $this = $(this);
				$this.addClass(o.panelClass);
			});

			// Selected tab
			// use "selected" option or try to retrieve:
			// 1. from fragment identifier in url
			// 2. from cookie
			// 3. from selected class attribute on <li>
			if (o.selected === undefined) {
				if (location.hash) {
					this.$tabs.each(function(i, a) {
						if (a.hash == location.hash) {
							o.selected = i;
							// prevent page scroll to fragment
							if ($.browser.msie || $.browser.opera) { // && !o.remote
								var $toShow = $(location.hash), toShowId = $toShow.attr('id');
								$toShow.attr('id', '');
								setTimeout(function() {
									$toShow.attr('id', toShowId); // restore id
								}, 500);
							}
							scrollTo(0, 0);
							return false; // break
						}
					});
				}
				else if (o.cookie) {
					var index = parseInt($.cookie('ui-tabs' + $.data(self.element)),10);
					if (index && self.$tabs[index])
						o.selected = index;
				}
				else if (self.$lis.filter('.' + o.selectedClass).length)
					o.selected = self.$lis.index( self.$lis.filter('.' + o.selectedClass)[0] );
			}
			o.selected = o.selected === null || o.selected !== undefined ? o.selected : 0; // first tab selected by default

			// Take disabling tabs via class attribute from HTML
			// into account and update option properly.
			// A selected tab cannot become disabled.
			o.disabled = $.unique(o.disabled.concat(
				$.map(this.$lis.filter('.' + o.disabledClass),
					function(n, i) { return self.$lis.index(n); } )
			)).sort();
			if ($.inArray(o.selected, o.disabled) != -1)
				o.disabled.splice($.inArray(o.selected, o.disabled), 1);
			
			// highlight selected tab
			this.$panels.addClass(o.hideClass);
			this.$lis.removeClass(o.selectedClass);
			if (o.selected !== null) {
				this.$panels.eq(o.selected).show().removeClass(o.hideClass); // use show and remove class to show in any case no matter how it has been hidden before
				this.$lis.eq(o.selected).addClass(o.selectedClass);
				
				// seems to be expected behavior that the show callback is fired
				var onShow = function() {
					self.trigger('show', null,
						self.ui(self.$tabs[o.selected], self.$panels[o.selected]));
				};

				// load if remote tab
				if ($.data(this.$tabs[o.selected], 'load.tabs'))
					this.load(o.selected, onShow);
				// just trigger show event
				else
					onShow();
			}
			
			// clean up to avoid memory leaks in certain versions of IE 6
			$(window).bind('unload', function() {
				self.$tabs.unbind('.tabs');
				self.$lis = self.$tabs = self.$panels = null;
			});

		}

		// disable tabs
		for (var i = 0, li; li = this.$lis[i]; i++)
			$(li)[$.inArray(i, o.disabled) != -1 && !$(li).hasClass(o.selectedClass) ? 'addClass' : 'removeClass'](o.disabledClass);

		// reset cache if switching from cached to not cached
		if (o.cache === false)
			this.$tabs.removeData('cache.tabs');
		
		// set up animations
		var hideFx, showFx, baseFx = { 'min-width': 0, duration: 1 }, baseDuration = 'normal';
		if (o.fx && o.fx.constructor == Array)
			hideFx = o.fx[0] || baseFx, showFx = o.fx[1] || baseFx;
		else
			hideFx = showFx = o.fx || baseFx;

		// reset some styles to maintain print style sheets etc.
		var resetCSS = { display: '', overflow: '', height: '' };
		if (!$.browser.msie) // not in IE to prevent ClearType font issue
			resetCSS.opacity = '';

		// Hide a tab, animation prevents browser scrolling to fragment,
		// $show is optional.
		function hideTab(clicked, $hide, $show) {
			$hide.animate(hideFx, hideFx.duration || baseDuration, function() { //
				$hide.addClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
				if ($.browser.msie && hideFx.opacity)
					$hide[0].style.filter = '';
				if ($show)
					showTab(clicked, $show, $hide);
			});
		}

		// Show a tab, animation prevents browser scrolling to fragment,
		// $hide is optional.
		function showTab(clicked, $show, $hide) {
			if (showFx === baseFx)
				$show.css('display', 'block'); // prevent occasionally occuring flicker in Firefox cause by gap between showing and hiding the tab panels
			$show.animate(showFx, showFx.duration || baseDuration, function() {
				$show.removeClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
				if ($.browser.msie && showFx.opacity)
					$show[0].style.filter = '';

				// callback
				self.trigger('show', null, self.ui(clicked, $show[0]));
			});
		}

		// switch a tab
		function switchTab(clicked, $li, $hide, $show) {
			/*if (o.bookmarkable && trueClick) { // add to history only if true click occured, not a triggered click
				$.ajaxHistory.update(clicked.hash);
			}*/
			$li.addClass(o.selectedClass)
				.siblings().removeClass(o.selectedClass);
			hideTab(clicked, $hide, $show);
		}

		// attach tab event handler, unbind to avoid duplicates from former tabifying...
		this.$tabs.unbind('.tabs').bind(o.event, function() {

			//var trueClick = e.clientX; // add to history only if true click occured, not a triggered click
			var $li = $(this).parents('li:eq(0)'),
				$hide = self.$panels.filter(':visible'),
				$show = $(this.hash);

			// If tab is already selected and not unselectable or tab disabled or 
			// or is already loading or click callback returns false stop here.
			// Check if click handler returns false last so that it is not executed
			// for a disabled or loading tab!
			if (($li.hasClass(o.selectedClass) && !o.unselect)
				|| $li.hasClass(o.disabledClass) 
				|| $(this).hasClass(o.loadingClass)
				|| self.trigger('select', null, self.ui(this, $show[0])) === false
				) {
				this.blur();
				return false;
			}

			self.options.selected = self.$tabs.index(this);

			// if tab may be closed
			if (o.unselect) {
				if ($li.hasClass(o.selectedClass)) {
					self.options.selected = null;
					$li.removeClass(o.selectedClass);
					self.$panels.stop();
					hideTab(this, $hide);
					this.blur();
					return false;
				} else if (!$hide.length) {
					self.$panels.stop();
					var a = this;
					self.load(self.$tabs.index(this), function() {
						$li.addClass(o.selectedClass).addClass(o.unselectClass);
						showTab(a, $show);
					});
					this.blur();
					return false;
				}
			}

			if (o.cookie)
				$.cookie('ui-tabs' + $.data(self.element), self.options.selected, o.cookie);

			// stop possibly running animations
			self.$panels.stop();

			// show new tab
			if ($show.length) {

				// prevent scrollbar scrolling to 0 and than back in IE7, happens only if bookmarking/history is enabled
				/*if ($.browser.msie && o.bookmarkable) {
					var showId = this.hash.replace('#', '');
					$show.attr('id', '');
					setTimeout(function() {
						$show.attr('id', showId); // restore id
					}, 0);
				}*/

				var a = this;
				self.load(self.$tabs.index(this), $hide.length ? 
					function() {
						switchTab(a, $li, $hide, $show);
					} :
					function() {
						$li.addClass(o.selectedClass);
						showTab(a, $show);
					}
				);

				// Set scrollbar to saved position - need to use timeout with 0 to prevent browser scroll to target of hash
				/*var scrollX = window.pageXOffset || document.documentElement && document.documentElement.scrollLeft || document.body.scrollLeft || 0;
				var scrollY = window.pageYOffset || document.documentElement && document.documentElement.scrollTop || document.body.scrollTop || 0;
				setTimeout(function() {
					scrollTo(scrollX, scrollY);
				}, 0);*/

			} else
				throw 'jQuery UI Tabs: Mismatching fragment identifier.';

			// Prevent IE from keeping other link focussed when using the back button
			// and remove dotted border from clicked link. This is controlled in modern
			// browsers via CSS, also blur removes focus from address bar in Firefox
			// which can become a usability and annoying problem with tabsRotate.
			if ($.browser.msie)
				this.blur();

			//return o.bookmarkable && !!trueClick; // convert trueClick == undefined to Boolean required in IE
			return false;

		});

		// disable click if event is configured to something else
		if (!(/^click/).test(o.event))
			this.$tabs.bind('click.tabs', function() { return false; });

	},
	add: function(url, label, index) {
		if (index == undefined) 
			index = this.$tabs.length; // append by default

		var o = this.options;
		var $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label));
		$li.data('destroy.tabs', true);

		var id = url.indexOf('#') == 0 ? url.replace('#', '') : this.tabId( $('a:first-child', $li)[0] );

		// try to find an existing element before creating a new one
		var $panel = $('#' + id);
		if (!$panel.length) {
			$panel = $(o.panelTemplate).attr('id', id)
				.addClass(o.hideClass)
				.data('destroy.tabs', true);
		}
		$panel.addClass(o.panelClass);
		if (index >= this.$lis.length) {
			$li.appendTo(this.element);
			$panel.appendTo(this.element[0].parentNode);
		} else {
			$li.insertBefore(this.$lis[index]);
			$panel.insertBefore(this.$panels[index]);
		}
		
		o.disabled = $.map(o.disabled,
			function(n, i) { return n >= index ? ++n : n });
			
		this.tabify();

		if (this.$tabs.length == 1) {
			$li.addClass(o.selectedClass);
			$panel.removeClass(o.hideClass);
			var href = $.data(this.$tabs[0], 'load.tabs');
			if (href)
				this.load(index, href);
		}

		// callback
		this.trigger('add', null, this.ui(this.$tabs[index], this.$panels[index]));
	},
	remove: function(index) {
		var o = this.options, $li = this.$lis.eq(index).remove(),
			$panel = this.$panels.eq(index).remove();

		// If selected tab was removed focus tab to the right or
		// in case the last tab was removed the tab to the left.
		if ($li.hasClass(o.selectedClass) && this.$tabs.length > 1)
			this.select(index + (index + 1 < this.$tabs.length ? 1 : -1));

		o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }),
			function(n, i) { return n >= index ? --n : n });

		this.tabify();

		// callback
		this.trigger('remove', null, this.ui($li.find('a')[0], $panel[0]));
	},
	enable: function(index) {
		var o = this.options;
		if ($.inArray(index, o.disabled) == -1)
			return;
			
		var $li = this.$lis.eq(index).removeClass(o.disabledClass);
		if ($.browser.safari) { // fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2...
			$li.css('display', 'inline-block');
			setTimeout(function() {
				$li.css('display', 'block');
			}, 0);
		}

		o.disabled = $.grep(o.disabled, function(n, i) { return n != index; });

		// callback
		this.trigger('enable', null, this.ui(this.$tabs[index], this.$panels[index]));
	},
	disable: function(index) {
		var self = this, o = this.options;
		if (index != o.selected) { // cannot disable already selected tab
			this.$lis.eq(index).addClass(o.disabledClass);

			o.disabled.push(index);
			o.disabled.sort();

			// callback
			this.trigger('disable', null, this.ui(this.$tabs[index], this.$panels[index]));
		}
	},
	select: function(index) {
		if (typeof index == 'string')
			index = this.$tabs.index( this.$tabs.filter('[href$=' + index + ']')[0] );
		this.$tabs.eq(index).trigger(this.options.event);
	},
	load: function(index, callback) { // callback is for internal usage only
		
		var self = this, o = this.options, $a = this.$tabs.eq(index), a = $a[0],
				bypassCache = callback == undefined || callback === false, url = $a.data('load.tabs');

		callback = callback || function() {};
		
		// no remote or from cache - just finish with callback
		if (!url || !bypassCache && $.data(a, 'cache.tabs')) {
			callback();
			return;
		}

		// load remote from here on
		
		var inner = function(parent) {
			var $parent = $(parent), $inner = $parent.find('*:last');
			return $inner.length && $inner.is(':not(img)') && $inner || $parent;
		};
		var cleanup = function() {
			self.$tabs.filter('.' + o.loadingClass).removeClass(o.loadingClass)
						.each(function() {
							if (o.spinner)
								inner(this).parent().html(inner(this).data('label.tabs'));
						});
			self.xhr = null;
		};
		
		if (o.spinner) {
			var label = inner(a).html();
			inner(a).wrapInner('<em></em>')
				.find('em').data('label.tabs', label).html(o.spinner);
		}

		var ajaxOptions = $.extend({}, o.ajaxOptions, {
			url: url,
			success: function(r, s) {
				$(a.hash).html(r);
				cleanup();
				
				if (o.cache)
					$.data(a, 'cache.tabs', true); // if loaded once do not load them again

				// callbacks
				self.trigger('load', null, self.ui(self.$tabs[index], self.$panels[index]));
				o.ajaxOptions.success && o.ajaxOptions.success(r, s);
				
				// This callback is required because the switch has to take
				// place after loading has completed. Call last in order to 
				// fire load before show callback...
				callback();
			}
		});
		if (this.xhr) {
			// terminate pending requests from other tabs and restore tab label
			this.xhr.abort();
			cleanup();
		}
		$a.addClass(o.loadingClass);
		setTimeout(function() { // timeout is again required in IE, "wait" for id being restored
			self.xhr = $.ajax(ajaxOptions);
		}, 0);

	},
	url: function(index, url) {
		this.$tabs.eq(index).removeData('cache.tabs').data('load.tabs', url);
	},
	destroy: function() {
		var o = this.options;
		this.element.unbind('.tabs')
			.removeClass(o.navClass).removeData('tabs');
		this.$tabs.each(function() {
			var href = $.data(this, 'href.tabs');
			if (href)
				this.href = href;
			var $this = $(this).unbind('.tabs');
			$.each(['href', 'load', 'cache'], function(i, prefix) {
				$this.removeData(prefix + '.tabs');
			});
		});
		this.$lis.add(this.$panels).each(function() {
			if ($.data(this, 'destroy.tabs'))
				$(this).remove();
			else
				$(this).removeClass([o.selectedClass, o.unselectClass,
					o.disabledClass, o.panelClass, o.hideClass].join(' '));
		});
	}
});

$.ui.tabs.defaults = {
	// basic setup
	unselect: false,
	event: 'click',
	disabled: [],
	cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
	// TODO history: false,

	// Ajax
	spinner: 'Loading&#8230;',
	cache: false,
	idPrefix: 'ui-tabs-',
	ajaxOptions: {},

	// animations
	fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }

	// templates
	tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>',
	panelTemplate: '<div></div>',

	// CSS classes
	navClass: 'ui-tabs-nav',
	selectedClass: 'ui-tabs-selected',
	unselectClass: 'ui-tabs-unselect',
	disabledClass: 'ui-tabs-disabled',
	panelClass: 'ui-tabs-panel',
	hideClass: 'ui-tabs-hide',
	loadingClass: 'ui-tabs-loading'
};

$.ui.tabs.getter = "length";

/*
 * Tabs Extensions
 */

/*
 * Rotate
 */
$.extend($.ui.tabs.prototype, {
	rotation: null,
	rotate: function(ms, continuing) {
		
		continuing = continuing || false;
		
		var self = this, t = this.options.selected;
		
		function start() {
			self.rotation = setInterval(function() {
				t = ++t < self.$tabs.length ? t : 0;
				self.select(t);
			}, ms); 
		}
		
		function stop(e) {
			if (!e || e.clientX) { // only in case of a true click
				clearInterval(self.rotation);
			}
		}
		
		// start interval
		if (ms) {
			start();
			if (!continuing)
				this.$tabs.bind(this.options.event, stop);
			else
				this.$tabs.bind(this.options.event, function() {
					stop();
					t = self.options.selected;
					start();
				});
		}
		// stop interval
		else {
			stop();
			this.$tabs.unbind(this.options.event, stop);
		}
	}
});

})(jQuery);

(function(b){var c,a=[];function e(g,f,i){var h;h=b.fn[f];b.fn[f]=function(){var j;if(g!=="after"){j=i.apply(this,arguments);if(j!==undefined){return j}}j=h.apply(this,arguments);if(g!=="before"){i.apply(this,arguments)}return j}}b.fn.tinymce=function(i){var h=this,g,j="",f;if(!h.length){return}if(!i){return tinyMCE.get(this[0].id)}function k(){if(d){d();d=null}h.each(function(m,p){var l,o=p.id||tinymce.DOM.uniqueId();p.id=o;l=new tinymce.Editor(o,i);l.render()})}if(!window.tinymce&&!c&&(g=i.script_url)){c=1;if(/_(src|dev)\.js/g.test(g)){j="_src"}window.tinyMCEPreInit={base:g.substring(0,g.lastIndexOf("/")),suffix:j,query:""};b.getScript(g,function(){tinymce.dom.Event.domLoaded=1;c=2;k();b.each(a,function(l,m){m()})})}else{if(c===1){a.push(k)}else{k()}}};b.extend(b.expr[":"],{tinymce:function(f){return f.id&&!!tinyMCE.get(f.id)}});function d(){function f(){this.find("span.mceEditor,div.mceEditor").each(function(j,k){var h;if(h=tinyMCE.get(k.id.replace(/_parent$/,""))){h.remove()}})}function g(i){var h;if(i!==undefined){f.call(this);this.each(function(k,l){var j;if(j=tinyMCE.get(l.id)){j.setContent(i)}})}else{if(this.length>0){if(h=tinyMCE.get(this[0].id)){return h.getContent()}}}}e("both","text",function(h){if(h!==undefined){return g.call(this,h)}if(this.length>0){if(ed=tinyMCE.get(this[0].id)){return ed.getContent().replace(/<[^>]+>/g,"")}}});b.each(["val","html"],function(j,h){e("both",h,g)});b.each(["append","prepend"],function(j,h){e("before",h,function(i){if(i!==undefined){this.each(function(l,m){var k;if(k=tinyMCE.get(m.id)){if(h==="append"){k.setContent(k.getContent()+i)}else{k.setContent(i+k.getContent())}}})}})});e("both","attr",function(h,i){if(h&&h==="value"){return g.call(this,i)}});b.each(["remove","replaceWith","replaceAll","empty"],function(j,h){e("before",h,f)})}})(jQuery);
/*
 * jQuery Color Animations
 * Copyright 2007 John Resig
 * Released under the MIT and GPL licenses.
 */

(function(jQuery){

	// We override the animation for all of these color styles
	jQuery.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'], function(i,attr){
		jQuery.fx.step[attr] = function(fx){
			if ( fx.state == 0 ) {
				fx.start = getColor( fx.elem, attr );
				fx.end = getRGB( fx.end );
			}

			fx.elem.style[attr] = "rgb(" + [
				Math.max(Math.min( parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0]), 255), 0),
				Math.max(Math.min( parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1]), 255), 0),
				Math.max(Math.min( parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2]), 255), 0)
			].join(",") + ")";
		}
	});

	// Color Conversion functions from highlightFade
	// By Blair Mitchelmore
	// http://jquery.offput.ca/highlightFade/

	// Parse strings looking for color tuples [255,255,255]
	function getRGB(color) {
		var result;

		// Check if we're already dealing with an array of colors
		if ( color && color.constructor == Array && color.length == 3 )
			return color;

		// Look for rgb(num,num,num)
		if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))
			return [parseInt(result[1]), parseInt(result[2]), parseInt(result[3])];

		// Look for rgb(num%,num%,num%)
		if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))
			return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];

		// Look for #a0b1c2
		if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))
			return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];

		// Look for #fff
		if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))
			return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];

		// Otherwise, we're most likely dealing with a named color
		return colors[jQuery.trim(color).toLowerCase()];
	}
	
	function getColor(elem, attr) {
		var color;

		do {
			color = jQuery.curCSS(elem, attr);

			// Keep going until we find an element that has color, or we hit the body
			if ( color != '' && color != 'transparent' || jQuery.nodeName(elem, "body") )
				break; 

			attr = "backgroundColor";
		} while ( elem = elem.parentNode );

		return getRGB(color);
	};
	
	// Some named colors to work with
	// From Interface by Stefan Petre
	// http://interface.eyecon.ro/

	var colors = {
		aqua:[0,255,255],
		azure:[240,255,255],
		beige:[245,245,220],
		black:[0,0,0],
		blue:[0,0,255],
		brown:[165,42,42],
		cyan:[0,255,255],
		darkblue:[0,0,139],
		darkcyan:[0,139,139],
		darkgrey:[169,169,169],
		darkgreen:[0,100,0],
		darkkhaki:[189,183,107],
		darkmagenta:[139,0,139],
		darkolivegreen:[85,107,47],
		darkorange:[255,140,0],
		darkorchid:[153,50,204],
		darkred:[139,0,0],
		darksalmon:[233,150,122],
		darkviolet:[148,0,211],
		fuchsia:[255,0,255],
		gold:[255,215,0],
		green:[0,128,0],
		indigo:[75,0,130],
		khaki:[240,230,140],
		lightblue:[173,216,230],
		lightcyan:[224,255,255],
		lightgreen:[144,238,144],
		lightgrey:[211,211,211],
		lightpink:[255,182,193],
		lightyellow:[255,255,224],
		lime:[0,255,0],
		magenta:[255,0,255],
		maroon:[128,0,0],
		navy:[0,0,128],
		olive:[128,128,0],
		orange:[255,165,0],
		pink:[255,192,203],
		purple:[128,0,128],
		violet:[128,0,128],
		red:[255,0,0],
		silver:[192,192,192],
		white:[255,255,255],
		yellow:[255,255,0]
	};
	
})(jQuery);

/**
 * WYSIWYG - jQuery plugin 0.5
 *
 * Copyright (c) 2008-2009 Juan M Martinez
 * http://plugins.jquery.com/project/jWYSIWYG
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * $Id: $
 */
(function( $ )
{
    $.fn.document = function()
    {
        var element = this[0];

        if ( element.nodeName.toLowerCase() == 'iframe' )
            return element.contentWindow.document;
            /*
            return ( $.browser.msie )
                ? document.frames[element.id].document
                : element.contentWindow.document // contentDocument;
             */
        else
            return $(this);
    };

    $.fn.documentSelection = function()
    {
        var element = this[0];

        if ( element.contentWindow.document.selection )
            return element.contentWindow.document.selection.createRange().text;
        else
            return element.contentWindow.getSelection().toString();
    };

    $.fn.wysiwyg = function( options )
    {
        if ( arguments.length > 0 && arguments[0].constructor == String )
        {
            var action = arguments[0].toString();
            var params = [];

            for ( var i = 1; i < arguments.length; i++ )
                params[i - 1] = arguments[i];

            if ( action in Wysiwyg )
            {
                return this.each(function()
                {
                    $.data(this, 'wysiwyg')
                     .designMode();

                    Wysiwyg[action].apply(this, params);
                });
            }
            else return this;
        }

        var controls = {};

        /**
         * If the user set custom controls, we catch it, and merge with the
         * defaults controls later.
         */
        if ( options && options.controls )
        {
            var controls = options.controls;
            delete options.controls;
        }

        var options = $.extend({
            html : '<'+'?xml version="1.0" encoding="UTF-8"?'+'><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">STYLE_SHEET</head><body>INITIAL_CONTENT</body></html>',
            css  : {},

            debug        : false,

            autoSave     : true,  // http://code.google.com/p/jwysiwyg/issues/detail?id=11
            rmUnwantedBr : true,  // http://code.google.com/p/jwysiwyg/issues/detail?id=15
            brIE         : true,

            controls : {},
            messages : {}
        }, options);

        options.messages = $.extend(true, options.messages, Wysiwyg.MSGS_EN);
        options.controls = $.extend(true, options.controls, Wysiwyg.TOOLBAR);

        for ( var control in controls )
        {
            if ( control in options.controls )
                $.extend(options.controls[control], controls[control]);
            else
                options.controls[control] = controls[control];
        }

        // not break the chain
        return this.each(function()
        {
            Wysiwyg(this, options);
        });
    };

    function Wysiwyg( element, options )
    {
        return this instanceof Wysiwyg
            ? this.init(element, options)
            : new Wysiwyg(element, options);
    }

    $.extend(Wysiwyg, {
        insertImage : function( szURL, attributes )
        {
            var self = $.data(this, 'wysiwyg');

            if ( self.constructor == Wysiwyg && szURL && szURL.length > 0 )
            {
                if ( attributes )
                {
                    self.editorDoc.execCommand('insertImage', false, '#jwysiwyg#');
                    var img = self.getElementByAttributeValue('img', 'src', '#jwysiwyg#');

                    if ( img )
                    {
                        img.src = szURL;

                        for ( var attribute in attributes )
                        {
                            img.setAttribute(attribute, attributes[attribute]);
                        }
                    }
                }
                else
                {
                    self.editorDoc.execCommand('insertImage', false, szURL);
                }
            }
        },

        createLink : function( szURL )
        {
            var self = $.data(this, 'wysiwyg');

            if ( self.constructor == Wysiwyg && szURL && szURL.length > 0 )
            {
                var selection = $(self.editor).documentSelection();

                if ( selection.length > 0 )
                {
                    self.editorDoc.execCommand('unlink', false, []);
                    self.editorDoc.execCommand('createLink', false, szURL);
                }
                else if ( self.options.messages.nonSelection )
                    alert(self.options.messages.nonSelection);
            }
        },

        setContent : function( newContent )
        {
            var self = $.data(this, 'wysiwyg');
                self.setContent( newContent );
                self.saveContent();
        },

        clear : function()
        {
            var self = $.data(this, 'wysiwyg');
                self.setContent('');
                self.saveContent();
        },

        MSGS_EN : {
            nonSelection : 'select the text you wish to link'
        },

        TOOLBAR : {
            bold          : { visible : true, tags : ['b', 'strong'], css : { fontWeight : 'bold' } },
            italic        : { visible : true, tags : ['i', 'em'], css : { fontStyle : 'italic' } },
            strikeThrough : { visible : false, tags : ['s', 'strike'], css : { textDecoration : 'line-through' } },
            underline     : { visible : false, tags : ['u'], css : { textDecoration : 'underline' } },

            separator00 : { visible : false, separator : true },

            justifyLeft   : { visible : false, css : { textAlign : 'left' } },
            justifyCenter : { visible : false, tags : ['center'], css : { textAlign : 'center' } },
            justifyRight  : { visible : false, css : { textAlign : 'right' } },
            justifyFull   : { visible : false, css : { textAlign : 'justify' } },

            separator01 : { visible : false, separator : true },

            indent  : { visible : false },
            outdent : { visible : false },

            separator02 : { visible : false, separator : true },

            subscript   : { visible : false, tags : ['sub'] },
            superscript : { visible : false, tags : ['sup'] },

            separator03 : { visible : false, separator : true },

            undo : { visible : false },
            redo : { visible : false },

            separator04 : { visible : false, separator : true },

            insertOrderedList    : { visible : false, tags : ['ol'] },
            insertUnorderedList  : { visible : false, tags : ['ul'] },
            insertHorizontalRule : { visible : false, tags : ['hr'] },

            separator05 : { separator : true },

            createLink : {
                visible : true,
                exec    : function()
                {
                    var selection = $(this.editor).documentSelection();

                    if ( selection.length > 0 )
                    {
                        if ( $.browser.msie )
                            this.editorDoc.execCommand('createLink', true, null);
                        else
                        {
                            var szURL = prompt('URL', 'http://');

                            if ( szURL && szURL.length > 0 )
                            {
                                this.editorDoc.execCommand('unlink', false, []);
                                this.editorDoc.execCommand('createLink', false, szURL);
                            }
                        }
                    }
                    else if ( this.options.messages.nonSelection )
                        alert(this.options.messages.nonSelection);
                },

                tags : ['a']
            },

            insertImage : {
                visible : true,
                exec    : function()
                {
                    if ( $.browser.msie )
                        this.editorDoc.execCommand('insertImage', true, null);
                    else
                    {
                        var szURL = prompt('URL', 'http://');

                        if ( szURL && szURL.length > 0 )
                            this.editorDoc.execCommand('insertImage', false, szURL);
                    }
                },

                tags : ['img']
            },

            separator06 : { separator : true },

            h1mozilla : { visible : true && $.browser.mozilla, className : 'h1', command : 'heading', arguments : ['h1'], tags : ['h1'] },
            h2mozilla : { visible : true && $.browser.mozilla, className : 'h2', command : 'heading', arguments : ['h2'], tags : ['h2'] },
            h3mozilla : { visible : true && $.browser.mozilla, className : 'h3', command : 'heading', arguments : ['h3'], tags : ['h3'] },

            h1 : { visible : true && !( $.browser.mozilla ), className : 'h1', command : 'formatBlock', arguments : ['Heading 1'], tags : ['h1'] },
            h2 : { visible : true && !( $.browser.mozilla ), className : 'h2', command : 'formatBlock', arguments : ['Heading 2'], tags : ['h2'] },
            h3 : { visible : true && !( $.browser.mozilla ), className : 'h3', command : 'formatBlock', arguments : ['Heading 3'], tags : ['h3'] },

            separator07 : { visible : false, separator : true },

            cut   : { visible : false },
            copy  : { visible : false },
            paste : { visible : false },

            separator08 : { separator : true && !( $.browser.msie ) },

            increaseFontSize : { visible : true && !( $.browser.msie ), tags : ['big'] },
            decreaseFontSize : { visible : true && !( $.browser.msie ), tags : ['small'] },

            separator09 : { separator : true },

            html : {
                visible : false,
                exec    : function()
                {
                    if ( this.viewHTML )
                    {
                        this.setContent( $(this.original).val() );
                        $(this.original).hide();
                    }
                    else
                    {
                        this.saveContent();
                        $(this.original).show();
                    }

                    this.viewHTML = !( this.viewHTML );
                }
            },

            removeFormat : {
                visible : true,
                exec    : function()
                {
                    this.editorDoc.execCommand('removeFormat', false, []);
                    this.editorDoc.execCommand('unlink', false, []);
                }
            }
        }
    });

    $.extend(Wysiwyg.prototype,
    {
        original : null,
        options  : {},

        element  : null,
        editor   : null,

        init : function( element, options )
        {
            var self = this;

            this.editor = element;
            this.options = options || {};

            $.data(element, 'wysiwyg', this);

            var newX = element.width || element.clientWidth;
            var newY = element.height || element.clientHeight;

            if ( element.nodeName.toLowerCase() == 'textarea' )
            {
                this.original = element;

                if ( newX == 0 && element.cols )
                    newX = ( element.cols * 8 ) + 21;

                if ( newY == 0 && element.rows )
                    newY = ( element.rows * 16 ) + 16;

                var editor = this.editor = $('<iframe></iframe>').css({
                    minHeight : ( newY - 6 ).toString() + 'px',
                    width     : ( newX - 8 ).toString() + 'px'
                }).attr('id', $(element).attr('id') + 'IFrame');

                if ( $.browser.msie )
                {
                    this.editor
                        .css('height', ( newY ).toString() + 'px');

                    /**
                    var editor = $('<span></span>').css({
                        width     : ( newX - 6 ).toString() + 'px',
                        height    : ( newY - 8 ).toString() + 'px'
                    }).attr('id', $(element).attr('id') + 'IFrame');

                    editor.outerHTML = this.editor.outerHTML;
                     */
                }
            }

            var panel = this.panel = $('<ul></ul>').addClass('panel');

            this.appendControls();
            this.element = $('<div></div>').css({
                width : ( newX > 0 ) ? ( newX ).toString() + 'px' : '100%'
            }).addClass('wysiwyg')
              .append(panel)
              .append( $('<div><!-- --></div>').css({ clear : 'both' }) )
              .append(editor);

            $(element)
            // .css('display', 'none')
            .hide()
            .before(this.element);

            this.viewHTML = false;

            this.initialHeight = newY - 8;

            /**
             * @link http://code.google.com/p/jwysiwyg/issues/detail?id=52
             */
            this.initialContent = $(element).val();

            this.initFrame();

            if ( this.initialContent.length == 0 )
                this.setContent('');

            if ( this.options.autoSave )
                $('form').submit(function() { self.saveContent(); });

            $('form').bind('reset', function()
            {
                self.setContent( self.initialContent );
                self.saveContent();
            });
        },

        initFrame : function()
        {
            var self = this;
            var style = '';

            /**
             * @link http://code.google.com/p/jwysiwyg/issues/detail?id=14
             */
            if ( this.options.css && this.options.css.constructor == String )
                style = '<link rel="stylesheet" type="text/css" media="screen" href="' + this.options.css + '" />';

            this.editorDoc = $(this.editor).document();
            this.editorDoc_designMode = false;

            try {
                this.editorDoc.designMode = 'on';
                this.editorDoc_designMode = true;
            } catch ( e ) {
                // Will fail on Gecko if the editor is placed in an hidden container element
                // The design mode will be set ones the editor is focused

                $(this.editorDoc).focus(function()
                {
                    self.designMode();
                });
            }

            this.editorDoc.open();
            this.editorDoc.write(
                this.options.html
                    .replace(/INITIAL_CONTENT/, this.initialContent)
                    .replace(/STYLE_SHEET/, style)
            );
            this.editorDoc.close();
            this.editorDoc.contentEditable = 'true';

            if ( $.browser.msie )
            {
                /**
                 * Remove the horrible border it has on IE.
                 */
                setTimeout(function() { $(self.editorDoc.body).css('border', 'none'); }, 0);
            }

            $(this.editorDoc).click(function( event )
            {
                self.checkTargets( event.target ? event.target : event.srcElement);
            });

            /**
             * @link http://code.google.com/p/jwysiwyg/issues/detail?id=20
             */
            $(this.original).focus(function()
            {
                $(self.editorDoc.body).focus();
            });

            if ( this.options.autoSave )
            {
                /**
                 * @link http://code.google.com/p/jwysiwyg/issues/detail?id=11
                 */
                $(this.editorDoc).keydown(function() { self.saveContent(); })
                                 .keyup(function() { self.saveContent(); })
                                 .mousedown(function() { self.saveContent(); });
            }

            if ( this.options.css )
            {
                setTimeout(function()
                {
                    if ( self.options.css.constructor == String )
                    {
                        /**
                         * $(self.editorDoc)
                         * .find('head')
                         * .append(
                         *     $('<link rel="stylesheet" type="text/css" media="screen" />')
                         *     .attr('href', self.options.css)
                         * );
                         */
                    }
                    else
                        $(self.editorDoc).find('body').css(self.options.css);
                }, 0);
            }

            $(this.editorDoc).keydown(function( event )
            {
                if ( $.browser.msie && self.options.brIE && event.keyCode == 13 )
                {
                    var rng = self.getRange();
                        rng.pasteHTML('<br />');
                        rng.collapse(false);
                        rng.select();

    				return false;
                }
            });
        },

        designMode : function()
        {
            if ( !( this.editorDoc_designMode ) )
            {
                try {
                    this.editorDoc.designMode = 'on';
                    this.editorDoc_designMode = true;
                } catch ( e ) {}
            }
        },

        getSelection : function()
        {
            return ( window.getSelection ) ? window.getSelection() : document.selection;
        },

        getRange : function()
        {
            var selection = this.getSelection();

            if ( !( selection ) )
                return null;

            return ( selection.rangeCount > 0 ) ? selection.getRangeAt(0) : selection.createRange();
        },

        getContent : function()
        {
            return $( $(this.editor).document() ).find('body').html();
        },

        setContent : function( newContent )
        {
            $( $(this.editor).document() ).find('body').html(newContent);
        },

        saveContent : function()
        {
            if ( this.original )
            {
                var content = this.getContent();

                if ( this.options.rmUnwantedBr )
                    content = ( content.substr(-4) == '<br>' ) ? content.substr(0, content.length - 4) : content;

                $(this.original).val(content);
            }
        },

        appendMenu : function( cmd, args, className, fn )
        {
            var self = this;
            var args = args || [];

            $('<li></li>').append(
                $('<a><!-- --></a>').addClass(className || cmd)
            ).mousedown(function() {
                if ( fn ) fn.apply(self); else self.editorDoc.execCommand(cmd, false, args);
                if ( self.options.autoSave ) self.saveContent();
            }).appendTo( this.panel );
        },

        appendMenuSeparator : function()
        {
            $('<li class="separator"></li>').appendTo( this.panel );
        },

        appendControls : function()
        {
            for ( var name in this.options.controls )
            {
                var control = this.options.controls[name];

                if ( control.separator )
                {
                    if ( control.visible !== false )
                        this.appendMenuSeparator();
                }
                else if ( control.visible )
                {
                    this.appendMenu(
                        control.command || name, control.arguments || [],
                        control.className || control.command || name || 'empty', control.exec
                    );
                }
            }
        },

        checkTargets : function( element )
        {
            for ( var name in this.options.controls )
            {
                var control = this.options.controls[name];
                var className = control.className || control.command || name || 'empty';

                $('.' + className, this.panel).removeClass('active');

                if ( control.tags )
                {
                    var elm = element;

                    do {
                        if ( elm.nodeType != 1 )
                            break;

                        if ( $.inArray(elm.tagName.toLowerCase(), control.tags) != -1 )
                            $('.' + className, this.panel).addClass('active');
                    } while ( elm = elm.parentNode );
                }

                if ( control.css )
                {
                    var elm = $(element);

                    do {
                        if ( elm[0].nodeType != 1 )
                            break;

                        for ( var cssProperty in control.css )
                            if ( elm.css(cssProperty).toString().toLowerCase() == control.css[cssProperty] )
                                $('.' + className, this.panel).addClass('active');
                    } while ( elm = elm.parent() );
                }
            }
        },

        getElementByAttributeValue : function( tagName, attributeName, attributeValue )
        {
            var elements = this.editorDoc.getElementsByTagName(tagName);

            for ( var i = 0; i < elements.length; i++ )
            {
                var value = elements[i].getAttribute(attributeName);

                if ( $.browser.msie )
                {
                    /** IE add full path, so I check by the last chars. */
                    value = value.substr(value.length - attributeValue.length);
                }

                if ( value == attributeValue )
                    return elements[i];
            }

            return false;
        }
    });
})(jQuery);
(function($) {
    $.fn.svEditableSection = function(options) {
        options = $.extend({
            onEditable: function() { },
            beforeSubmit: function() { return true; },
            onSuccess: function() { },
            onCancel: function() { },
            afterCancel: function() { },
            submitStyle: 'async',
            dataType: 'html',
            customValidation: {},
            warnOnExit: true,
            action: 'EDIT',
            disableValidation: false
        }, options);

        return new $.EditableSection(this, options);
    };

    $.EditableSection = function(element, options) {
        var self = this;
        var isOpen = false;

        var toggleEditor = function(id) {
            $('#' + id).toggle();
            $('#' + id + '-edit').toggle();
        };

        var hideEditor = function(id) {
            $('#' + id).show();
            $('#' + id + '-edit').hide();
        };

        var sectionId = $(element).attr('id');
        var editor = $('#' + sectionId + '-edit');
        var editable = $(element);
        var editor_form;

        var setupForm = function() {
            editor_form = editor.find('form').eq(0);
            editor_form.submit(function() {
                submitForm();
                return false;
            });

            options.customValidation = $.extend({
                errorPlacement: function(error, element) {
                    error.appendTo(element.parent().find(".errorHolder"));
                }
            }, options.customValidation);

            if (!options.disableValidation) {
                editor_form.validate(options.customValidation);
            }
        };

        var init = function() {
            // if initialized in CREATE mode then we should show the form
            if (options.action == 'CREATE') {
                beginEditing();
            }

            element.bind("refresh", function() {
                refresh();
            });
        };

        var beginEditing = function() {
            setupForm();
            toggleEditor(sectionId);
            options.onEditable();
            adjustOpenEditorCount(+1);
            isOpen = true;
        };

        var closeEditor = function() {
            hideEditor(sectionId);
            adjustOpenEditorCount(-1);
            isOpen = false;
        }

        var adjustOpenEditorCount = function(adjustment) {
            if (options.submitStyle == 'async' && options.warnOnExit) {
                numOpenEditors = $('body').data('openEditors');
                numOpenEditors = isNaN(numOpenEditors) ? 0 : numOpenEditors;
                numOpenEditors += adjustment;
                $('body').data('openEditors', numOpenEditors);
            }
        };

        var refresh = function() {
            setupForm();
            var wasSync = options.submitStyle == 'sync';
            var appendData = '&noupdate=true';
            options.submitStyle = 'async';
            submitForm(appendData);
            if (wasSync) options.submitStyle = 'sync';
        };

        var disableLinks = function(e) {
            return false;
        };

        var formUpdateError = function(XMLHttpRequest, textStatus, errorThrown) {
            saveButton.html('save');
            alert('There was a problem while saving. Please try again.');
        };

        var formUpdateSuccess = function(data, textStatus) {
            saveButton.html('save');
            if (options.dataType == 'html') {
                if ($(data).html() != null) {
                    updateContent(data);
                    if (isOpen)
                        closeEditor();
                    options.onSuccess(editable);
                }
                else
                    formUpdateError(null, textStatus, null);
            }
            else if (options.dataType == 'json') {
                options.onSuccess(data, textStatus);
            }
        };

        var formUpdateComplete = function() {
            $('a').unbind("click", disableLinks);
        }

        var editButton = editable.find('a.edit_section').click(function() {
            beginEditing();
            return false;
        });

        var cancelButton = editor.find('a.cancel_edit').click(function() {
            options.onCancel();
            if (options.action == 'CREATE') {
                history.go(-1);
            }
            else {
                editor_form.each(function() { this.reset() });
                if (!options.disableValidation) {
                    editor_form.valid();
                }
                closeEditor();
            }
            options.afterCancel();
            return false;
        });

        var saveButton = editor.find('a.save_edit').click(function() {
            if (saveButton.html() != 'saving...') {
                submitForm();
            }
            return false;
        });

        var updateContent = function(data) {
            var new_editable = $(data).find('#' + sectionId + '-body');
            new_editor = $(data).find('#' + sectionId + '-edit-body');
            editable.find('#' + sectionId + '-body').html(new_editable.html());
            editor.find('#' + sectionId + '-edit-body').html(new_editor.html());
        }

        var submitForm = function(appendData) {
            if ((options.disableValidation || editor_form.valid()) && saveButton.html() != 'saving...') {
                if (options.beforeSubmit(editor_form) == true) {
                    $('a').bind("click", disableLinks);
                    saveButton.html('saving...');
                    if (options.submitStyle == 'async') {
                        var url = editor_form.attr('action');
                        var enctype = "application/x-www-form-urlencoded";
                        var data = editor_form.serialize();
                        if (appendData) {
                            data += appendData;
                        }
                        $.ajax({
                            complete: formUpdateComplete,
                            data: data,
                            dataType: options.dataType,
                            error: formUpdateError,
                            success: formUpdateSuccess,
                            contentType: enctype,
                            type: 'POST',
                            url: url
                        });
                    }
                    else {
                        editor_form[0].submit();
                    }
                }
            }
        };

        $.extend(this, {
            submit: function() {
                submitForm();
            },
            beginEditing: function() {
                beginEditing()
            },
            refresh: function() {
                refresh();
            }
        });

        jQuery(document).ready(init);
    };
})(jQuery);

(function($) {
    $.fn.svCompanyAutocomplete = function(options) {
        options = $.extend({
            onSet: function() { },
            fieldName: ''
        }, options);

        var COMPANY_NAME = 0;
        var COMPANY_DIVISION = 1;
        var COMPANY_ADDRESS = 2;
        var COMPANY_ID = 3;

        return this.each(function() {
            var control = $(this);

            var setResult = function(id, name, disableCallback) {
                control.data('id', id);
                control.data('name', name);

                var compIdInput;
                if (options.fieldName == '') {
                    compIdInput = $('#compId');
                }
                else {
                    compIdInput = $('input[name=' + options.fieldName + ']', control.parents().find('form'));
                }

                compIdInput.attr('value', id);
                if (parseInt(id) > 0) {
                    control.addClass('company_selected');
                }
                else {
                    control.removeClass('company_selected');
                }
                if (!disableCallback) {
                    options.onSet();
                }
            };

            control.autocomplete('contactmanager_organisationautocomplete.asp', {
                minChars: 2,
                selectFirst: false,
                formatItem: function(data, i, total, value) {
                    var item = '';
                    var name = data[COMPANY_NAME];
                    var division = data[COMPANY_DIVISION];
                    var address = data[COMPANY_ADDRESS];

                    item += '<span class=\'name\'>'
                    item += name;
                    item += division != '' ? ', ' + division : '';
                    item += '</span>';
                    item += address != '' ? '<br /><span class=\'address\'>' + address + '</span>' : '';

                    return item;
                },
                formatResult: function(data, i, total, value) {
                    var name = data[COMPANY_NAME];
                    var division = data[COMPANY_DIVISION];

                    var item = '';
                    item += name;

                    return item;
                },
                highlight: function(value, term) {
                    var terms = term.split(' ');
                    var highlitvalue = value;
                    $.each(terms, function(i, val) {
                        highlitvalue = highlitvalue.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + val.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
                    });
                    return highlitvalue;
                },
                extraParams: {
                    publickey: control.metadata().publickey
                }
            }).result(function(e, data, formatted) {
                var id = data[COMPANY_ID];
                var name = data[COMPANY_NAME];
                setResult(id, name);
            }).onchange(function() {
                setResult(0, '');
            });

            control.bind('set', function(obj, id, name, disableCallback) {
                control.val(name);
                setResult(id, name, disableCallback);
            });

            control.bind('reset', function() {
                control.val('');
                setResult(0, '');
            });
        });
    }
})(jQuery);



		
(function($) {
    $.fn.svPersonAutocomplete = function(options) {
        options = $.extend({
            onSet: function() { },
            fieldName: 'contId'
        }, options);
        var CONTACT_NAME = 0;
        var CONTACT_JOBTITLE = 1;
        var CONTACT_COMPANYNAME = 2;
        var CONTACT_ADDRESS = 3;
        var CONTACT_ID = 4;

        return this.each(function() {
            var control = $(this);

            var setResult = function(id, name, disableCallbacks) {
                control.data('id', id);
                control.data('name', name);
                var contIdInput = $('input[name=' + options.fieldName + ']', control.parents().find('form'));
                contIdInput.attr('value', id);
                if (parseInt(id) > 0) {
                    control.addClass('person_selected');
                }
                else {
                    control.removeClass('person_selected');
                }
                if (!disableCallbacks)
                    options.onSet();
            };

            control.autocomplete('contactmanager_personautocomplete.asp', {
                minChars: 2,
                selectFirst: false,
                formatItem: function(data, i, total, value) {
                    var item = '';
                    var name = data[CONTACT_NAME];
                    var jobtitle = data[CONTACT_JOBTITLE];
                    var companyname = data[CONTACT_COMPANYNAME];
                    var address = data[CONTACT_ADDRESS];

                    item += '<span class=\'name\'>'
                    item += name;
                    item += jobtitle != '' ? ', ' + jobtitle : '';
                    item += '</span>';
                    item += companyname != '' ? '<br /><span class=\'companyname\'>' + companyname + '</span>' : '';
                    item += address != '' ? '<br /><span class=\'address\'>' + address + '</span>' : '';

                    return item;
                },
                formatResult: function(data, i, total, value) {
                    var name = data[CONTACT_NAME];
                    return name;
                },
                highlight: function(value, term) {
                    var terms = term.split(' ');
                    var highlitvalue = value;
                    $.each(terms, function(i, val) {
                        highlitvalue = highlitvalue.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + val.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
                    });
                    return highlitvalue;
                }
            }).result(function(e, data, formatted) {
                var id = data[CONTACT_ID];
                setResult(id);
            }).onchange(function() {
                setResult(0);
            });

            control.bind('set', function(obj, id, name, disableCallbacks) {
                control.val(name);
                setResult(id, name, disableCallbacks);
            });
        });
    }
})(jQuery);



		
(function($) {
		  
	$.fn.svPersonHeader = function(options) {
		options = $.extend({
			onSuccess: function(){ return true;},
			warnOnExit: true,
			action: 'EDIT',
			dataType: 'html'
		}, options);
		
		return new $.PersonHeader(this, options);
	};
	
	$.PersonHeader = function(element, options) {
		
				
		var setup = function() {

			$('select.title').dxCombobox();
			$('#personaldetailssection-edit').find('form').svContactAddressManager();
			var updateaddressoptions = function() {
				if ($('#compId').attr("value") > 0) {
					$('.usecompanyaddress').attr("disabled", false);
					var address = '';
					$('input.address').each(function() {
						address += $(this).val();
					});
					if (address == '') {
						$('.usecompanyaddress').attr("checked", "checked").change();
					}
				}
				else {
					$('.usecompanyaddress').removeAttr("checked");
					$('.usecompanyaddress').attr("disabled", true);
					$('.useotheraddress').attr("checked", "checked");
				}
			};
			updateaddressoptions();
			$('#company').svCompanyAutocomplete({
				onSet: updateaddressoptions
			});
		};
		
		setup();

		var self = $(this);
		
		var isNameFilled = function() {
       		var $name = $('#contactname');
        	return $name.find('.required_group:filled').length;
    	};

    	$.validator.addMethod('required_group', isNameFilled, 'Please complete the first name, surname, or both.');

		var personaldetailssection = $('#personaldetailssection').svEditableSection({
			beforeSubmit: function(form) {
				var compId = $('#compId').attr('value');
				var compName = $('#company').attr('value');
	
				if (compId == '0' && compName != '') {
					var quickcompform = company_dialog.find('form');
					quickcompform.find('input.name').attr('value', compName);
					company_dialog.dialog("open");
					return false;
				}
				else {
					return true;
				}
			},
			customValidation: {
				'required_group': true,
				errorPlacement: function(error, element) {
					if (element.hasClass('required_group') && element.parent().parent().find('.errorHolder label').length == 0) {
						error.appendTo(element.parent().parent().find(".errorHolder"));
					}
					else {
						error.appendTo(element.parent().find(".errorHolder"));
					}
				}
			},
			onSuccess: function(response, textStatus){
				options.onSuccess(response, textStatus);
				setup();
			},
			warnOnExit: options.warnOnExit,
			action: options.action,
			dataType: options.dataType
		});
		
		var company_dialog = $('#createcompanymodal');
		company_dialog.svCreateCompanyModal({
			onSuccess: function(compId, compName) {
				if (compId > 0) {
					$("#compId").attr('value', compId);
					$("#company").attr('value', compName);
				}
				personaldetailssection.submit();
				return true;
			}
		});
		
	};
	
})(jQuery);
(function($) {
	$.fn.svAccountManagerSelector = function(options) {
		options = $.extend({
			url: 'nourl.asp',
			onSelect: function(accountManagerId, accountManager, salesTeamId, salesTeam){}
		}, options);
		
		return new $.AccountManagerSelector(this, options);
	};
	
	$.AccountManagerSelector = function(element, options) {
		var teamSelect = element.find('#teamSelect');
		var managerSelect = element.find('#managerSelect');
		var button = element.find('a.button');
		
		
		
		var updateComplete = function() {};
		
		var updateSuccess = function(data, textStatus) {
			managerSelect.removeOption(/./);
			managerSelect.addOption(0, 'Choose account manager...');
			var managers = 0;
			$.each(data.rows, function(i, item) {
				managerSelect.addOption(item.id, item.firstname + ' ' + item.surname);
				managers++;
			});
			managerSelect.selectOptions("0");
		};
		
		var updateError = function() {
			alert("There was a problem getting the team members. Please try again.");
		};
		
		teamSelect.change(function() {
			$.ajax({
				complete: updateComplete,
				data: {teamId: teamSelect.val()},
				dataType: 'json',
				error: updateError,
				success: updateSuccess,
				type:'POST',
				url: options.url
			});
		});
		
		var init = function() {
			button.unbind('click');
			button.click(function() {
				options.onSelect(managerSelect.val(), managerSelect.find('option:selected').text(), teamSelect.val(), teamSelect.find('option:selected').text());
				return false;
			});
		};
		
		init();
	};
})(jQuery);
(function($) {
	$.fn.svAccountManagerAssigner = function(options) {
		options = $.extend({
			input: null,
			format:''
		}, options);
		
		return new $.AccountManagerAssigner(this, options);
	};
	
	$.AccountManagerAssigner = function(element, options) {
		var self = this;
	
		var updateInput = function() {
			var items = $(element).find('.accountmanager');
			var listOfIds = '';
			items.each(function(index, element) {
				if (index > 0) { listOfIds += ','; }
				listOfIds += $(element).attr('id').replace(/accountmanager_/, '');
			});
			$(options.input).val(listOfIds);
		};
		
		var deleteAccountMan = function() {
			$(this).parent('div').remove();
			updateInput();
			return false;
		};
			
		$.extend(this, {
			init : function () {
				$(element).unbind('click');
				$(element).find('.deleteaccountman').each(function(index, domel) {
					$(domel).unbind('click');
					$(domel).click(deleteAccountMan);
				});
				$(element).find('.newitem').remove(); // remove any items that have been added already (ie items added and then user has click cancel)
			},
			addManager : function(accountManagerId, accountManager, salesTeamId, salesTeam) {
				if (parseInt(accountManagerId) > 0) {
					var removeLink = $('<a href=\"#\">remove</a>');
					
					removeLink.click(deleteAccountMan);
					a = $('<div class=\"accountmanager newitem\" id=\"accountmanager_' + salesTeamId + '|' + accountManagerId + '\">' + String.format(options.format, accountManagerId, accountManager, salesTeamId, salesTeam) + '</div>');
					$(element).append(a.append(removeLink));
					updateInput();
				}
			}
		});
		
		self.init();
	};
})(jQuery);
(function($) {
	$.fn.svActivityNote = function(options) {
		options = $.extend({
			newNote: false,
			beforeSubmit: function() {return true;},
			onSuccess: function() {},
			onCancel: function() {}
		}, options);
		
		return new $.svActivityNote(this, options);
	};
	
	$.svActivityNote = function(element, options) {
		var self = this;
		
		var editor = $(element).find('.activitynote-edit');
		var editor_form = $(editor.find('form')[0]);
		var note = $(element).find('.activitynote-body');
			
		var toggleEditor = function() {
			saveButton.toggle()
			editor.toggle();
			note.toggle();
			
			if (editButton.html() == 'edit') {
				var titleField = editor_form.get()[0].title
				titleField.focus();
				editButton.html('cancel');
				editButton.removeClass('editnote');
				editButton.addClass('cancelnote');
			}
			else {
				if (editButton.html()) {
					options.onCancel();
					editor.find('form')[0].reset();
					editButton.html('edit');
					editButton.removeClass('cancelnote');
					editButton.addClass('editnote');
				}
			}
		}
		
		var editButton = $(element).find('a.editnote').click(function() { 
			toggleEditor();
			return false;
		});
			
		var saveButton = $(element).find('a.savenote').click(function() {
			if (saveButton.html() != 'saving...') {
				submitForm();
			}
			return false;
		});
		
		var deleteButton = $(element).find('a.deletenote').click(function() {
			deleteNote(this);
			return false;
		});
			
		var submitForm = function() {
			var url = editor_form.attr('action');
			var data = editor_form.serialize();
			if (editor_form.valid()) {
				if (options.beforeSubmit(editor_form) == true) {
					saveButton.html('saving...');
					$.ajax({
						data: data,
						dataType: 'html',
						error: formUpdateError,
						success: formUpdateSuccess,
						type:'POST',
						url: url
					});

				}
			}
		};
		
		var formUpdateError = function() {
			alert('There was a problem while saving. Please try again.');
		};
		
		var formUpdateSuccess = function(data, textStatus) {
			options.onSuccess();	
		};
		
		$.extend(this, {
			submit : function() {
				submitForm()
			},
			openEditor : function() {
				toggleEditor();
			}
		});
		
		var deleteNote = function(a) {
			var url = deleteButton.attr("href");
			var noteId = deleteButton.metadata().noteId;
			var key = $(a).parent('form.deletenoteform').find('#key').attr("value");
			var data = {'noteId': noteId, 'noteKey': key};
			$.ajax({
				data: data,
				dataType: 'json',
				error: deleteNoteError,
				success: deleteNoteSuccess,
				type:'POST',
				url: url
			});
		};
		
		var deleteNoteError = function(data, textStatus) {
			alert('There was a problem while deleting. (' + data.errors + ')');
		};
		
		var deleteNoteSuccess = function(data, textStatus) {
			if(!data.success){
				deleteNoteError(data, textStatus);
			}
			else{		
				$('#activitynote_' + data.noteId).remove();
			}
		};
	};
})(jQuery);
//
// ======== svPicker jQuery Plugin example
// ======== ANY QUESTIONS refer to jo@siliconvine.com
// ======== 31/10/2008
//
/*
This plugin will handle the moving of selectbox options back and forth between select boxes. 
The hidden field is populated with the values of the options in the 'selected' box.

============= HTML =============

			<div id="dogbreedsselector">
				<div>
					<select id="dogbreedsselector_selected" size="10" multiple="multiple">
						<option value="1">Chow Chow</option>
						<option value="2">Alsation</option>
					</select>
					<input type="hidden" id="dogbreedsselector_selected_csv" value=""/>
				</div>
				<div id="dogbreedsselector_buttons">
				</div>
				<div>
					<select id="dogbreedsselector_available" size="10"  multiple="multiple">
						<option value="3">Rottweiler</option>
						<option value="4">Weimaraner</option>
					</select>
				</div>
			</div>
			
======= CALLING the svPicker PLUGIN ====================

$('#dogbreedsselector').svPicker({ 

	// note: picker_name should be the id of container
	   
						   		// mandatory
								idSelectBoxSelected:		'dogbreedsselector_selected',
								idSelectBoxAvailable:		'dogbreedsselector_available',
								idButtonContainer:  		'dogbreedsselector_buttons',
								idHiddenField:				'dogbreedsselector_selected_csv'
								
								// you may also specify the text for the buttons as 'txtImgButtonMoveLeft' and 'txtImgButtonMoveRight'
								});

*/

(function($) {
	$.fn.svPicker = function(options) {
			
		//default settings
		var settings = {
			txtImgButtonMoveLeft:			'<',
			txtImgButtonMoveRight:			'>',		
			idSelectBoxSelected:			'',
			idSelectBoxAvailable:			'',
			idButtonContainer:  			'',
			idHiddenField:					''
		}; //note: ids cannot be defaulted therefore and must be specified in the call
	
		//use specified settings if available
		if(options) {
			jQuery.extend(settings, options);
		};
			
		
		// FUNCTIONS
		
		// FUNCTION move
		// the buttons will call this function to move options between select lists, and update the hidden field which holds a csv of the option values currently in the 'selected' list at any given time
		
		function move(fromObject,toObject){
				var selectedOptions = fromObject.selectedOptions();

			try {
				selectedOptions.each(function(i){
											  var selectedop = $(this);
											  var addedop = toObject.addOption(selectedop.attr('value'), selectedop.attr('text'), false);
											  var removedop = fromObject.removeOption(selectedop.attr('value'),true);
											  });
			}
			catch(err) {
				alert(err.description);
			};		
			setCSV();
		}
		
		// FUNCTION setCsv
		function setCSV(){
			var concatCsvValues = "";
			$('#' + settings.idSelectBoxSelected + ' > option').each(function(index){
														  concatCsvValues += $(this).attr('value') + ',';
														  });
			concatCsvValues = concatCsvValues.substring(0,concatCsvValues.length - 1);
			$('#' + settings.idHiddenField).val(concatCsvValues);
		}
		
		// END FUNCTIONS
		
		//set up the CSV values in the hidden field 
		setCSV();
		
		//containing div
		var self = this;
		var SelectboxSelected = $('#' + settings.idSelectBoxSelected);
		var SelectboxAvailable = $('#' + settings.idSelectBoxAvailable);
			
		
		
		//buttons to move between boxes
		var buttons = $('#' + settings.idButtonContainer);
		var addButtonLeft = $('<input type=\'button\'></input>').val(settings.txtImgButtonMoveLeft)
																.click(function(){
																				var moveleft = move(SelectboxAvailable, SelectboxSelected);
																				return false;
																				});
		var addButtonRight = $('<input type=\'button\'></input>').val(settings.txtImgButtonMoveRight)
																.click(function(){
																					var moveright = move(SelectboxSelected, SelectboxAvailable);
																					return false;
																					});
		buttons.append(addButtonLeft).append(addButtonRight);

	
	
	};
})(jQuery);
// simply including this file will enable keepalive
$(function(){
	var keepalive_timeout = 600000;
	
	var keepAlive = function() {
		$.ajax({url:'keepalive.asp'});
		var k = setTimeout(keepAlive, keepalive_timeout);
	};
	var k = setTimeout(keepAlive, keepalive_timeout);
});
(function($) {
	$.fn.svProspectDetailsEditor = function(options) {
		options = $.extend({
			onSuccess: function(){return true;}
		}, options);
		
		return new $.ProspectDetailsEditor(this, options);
	};
	
	$.ProspectDetailsEditor = function(element, options) {
		var prospectnotes = false;
		
		var form = $(element).find('form');
		
		form.validate({
			rules: {
				value: {
					required: true,
					min: 0
				},
				likelihood: {
					required: true,
					min: 0,
					max: 100
				},
				date : {
					date: true
				}
			}
		});
		
		form.find('input.datepicker').datepicker({closeAtTop: false});
		
		element.dialog({
			autoOpen:false,
			open: function() {
				if (prospectnotes) { 	// there's a problem with jquery.wysiwyg that requires it not be initialised until the 
										// textare is visible. Here we make sure its not been initialized previously before doing so.
					//$('.wysiwyg').remove();					// See http://code.google.com/p/jwysiwyg/issues/detail?id=43
					
				}
				//prospectnotes = $('#prospectnotes').wysiwyg();
			},
			height:455,
			width:550,
			modal: true, 
			overlay: { 
				opacity: 0.5, 
				background: "black" 
			}
			

		});
		
		element.find('a.save').click(function() {
			if (form.valid()) {
				var url = form.attr('action');
				var data = form.serialize();
				
				$.ajax({
					complete: function() {},
					data: data,
					dataType: 'json',
					error: function() { alert('There was a problem while saving. Please try again.'); },
					success: function() {
						if (options.onSuccess())
							element.dialog("close");
					},
					type:'POST',
					url: url
				});
			}
			return false;
		});
		
		element.find('a.cancel').click(function() {
			element.dialog("close");
			return false;
		});
	
		$.extend(this, {
			dialog: function(settings) {
				element.dialog(settings);
			}
		});
	};
})(jQuery);
(function($) {
    $.fn.svSalesInfoEditor = function(options) {
        options = $.extend({
            onSuccess: function() { return true; }
        }, options);

        return new $.SalesInfoEditor(this, options);
    };

    $.SalesInfoEditor = function(element, options) {
        var fieldsDirty = false;

        var months = new Array(13);
        months[1] = "Jan";
        months[2] = "Feb";
        months[3] = "Mar";
        months[4] = "Apr";
        months[5] = "May";
        months[6] = "Jun";
        months[7] = "Jul";
        months[8] = "Aug";
        months[9] = "Sep";
        months[10] = "Oct";
        months[11] = "Nov";
        months[12] = "Dec";

        $('input.actual, input.predicted, select.salesstatus').change(function() { fieldsDirty = true; });

        var getSpend = function(month, year) {
            var input_actual = $('input.actual');
            var input_predicted = $('input.predicted');
            var select_status = $('select.salesstatus');

            // disable so user can't put new values in until we're ready
            input_actual.attr('disabled', 'disabled');
            input_predicted.attr('disabled', 'disabled');
            select_status.attr('disabled', 'disabled');

            var userId = $('input.userId').val();
            var url = 'salesmanager_json_salesinfo_edit.asp';
            var data = { month: month, year: year, userId: userId };
            $.ajax({
                url: url,
                data: data,
                dataType: 'json',
                complete: function() { input_actual.removeAttr('disabled'); input_predicted.removeAttr('disabled'); select_status.removeAttr('disabled'); },
                error: function() { alert('There was a problem loading the sales data for this month. Please try again.'); },
                success: function(data, Textstatus) {
                    var item = data.rows[0];
                    input_actual.val(item.actual);
                    input_predicted.val(item.predicted);
                    select_status.val(item.statusId);
                    fieldsDirty = false;
                },
                type: 'POST'
            });
        };

        var changemonth = function(delta) {
            saveDetails(false);

            var input_month = $('input.month');
            var input_year = $('input.year');
            var date_desciption = $('.date_desciption');

            var month = parseInt(input_month.val());
            var year = parseInt(input_year.val());

            month += delta;
            if (month > 12) {
                month = 1;
                year += 1;
            }
            if (month < 1) {
                month = 12;
                year -= 1;
            }

            input_month.val(month);
            input_year.val(year);

            date_desciption.html(months[month] + ' ' + year);

            getSpend(month, year);
        };
        $('#monthdown').click(function() { changemonth(-1); return false; });
        $('#monthup').click(function() { changemonth(+1); return false; });

        var prospectnotes = false;

        element.dialog({
            autoOpen: false,
            modal: true,
            overlay: {
                opacity: 0.5,
                background: "black"
            }
        });

        element.find('a.save').click(function() {
            saveDetails(true);
            return false;
        });

        function saveDetails(closeAfter) {
            if (fieldsDirty) {
                var form = element.find('form');
                var url = form.attr('action');
                var data = form.serialize();
                $.ajax({
                    complete: function() { },
                    data: data,
                    dataType: 'json',
                    error: function() { alert('There was a problem while saving. Please try again.'); },
                    success: function() {
                        fieldsDirty = false;
                        if (options.onSuccess() && closeAfter)
                            element.dialog("close");
                    },
                    type: 'POST',
                    url: url
                });
            }
        }

        element.find('a.cancel').click(function() {
            element.dialog("close");
            return false;
        });

        $.extend(this, {
            dialog: function(settings) {
                element.dialog(settings);
            }
        });
    };
})(jQuery);
(function($) {
	$.fn.svCreateCompanyModal = function(options) {
		options = $.extend({
			onSuccess: function(compId, compName){return true;}
		}, options);
		
		return new $.CreateCompanyModal(this, options);
	};
	
	$.CreateCompanyModal = function(element, options) {
		var self = $(this);

		var form = element.find('form');
		form.validate();
		
		var saveButton;
		
		var submitForm = function(e) {
			if (form.valid()) {
				if (e) {
					// if this is being called as part of a button click we can get the button. We'll need this to update the text. If it's not then we should have got it earlier so we'll be ok
					saveButton = $(e.target);
				}
				if (saveButton.html() != 'Saving...') {
					saveButton.html('Saving...');
					var url = form.attr('action');
					var data = form.serialize();
					
					var formUpdateComplete = function() { saveButton.html('Save'); };
					
					var formUpdateSucces = function(response, textStatus) {
						var compId = parseInt(response.data.id);
						var compName = response.data.name;
						if (options.onSuccess(compId, compName)) {
							element.dialog("close");
							form.each(function(){this.reset()});
						}
					};
					
					var formUpdateError = function(XMLHttpRequest, textStatus, errorThrown) {
						alert('There was a problem while saving. Please try again.');
					};
					
					$.ajax({
						complete: formUpdateComplete,
						data: data,
						dataType: 'json',
						error: formUpdateError,
						success: formUpdateSucces,
						type:'POST',
						url: url
					});
				}
			}
		};

		var theDialog = element.dialog({
			autoOpen: false,
			buttons: {
				"Save" : submitForm,
				"Cancel" : function() {
					$(this).dialog("close");
				}
			},
			height:540,
			modal: true, 
			overlay: { 
				opacity: 0.5, 
				background: "black" 
			},
			width:620
		});		   
	
		$.extend(theDialog, {
			/*dialog: function(settings) {
				element.dialog(settings);
			},*/
			populateForm: function(items) {
				for (var itemName in items) {
					form[0][itemName].value = items[itemName];
				}
			}
		});
	};
})(jQuery);
(function($) {
	var RTN_EMAILADDRESSEXISTS = -4;
	$.fn.svCreatePersonModal = function(options) {
		options = $.extend({
			beforeSubmit: function(form) {return true;},
			onSuccess: function(contId){return true;},
			disableOrgSelector: false
		}, options);
		
		return new $.CreatePersonModal(this, options);
	};
	
	$.CreatePersonModal = function(element, options) {
		var self = $(this);
		var introbox = $('#addpersonintro');
		var warningbox = $('#addpersonwarning');
		
		$('a.useperson', warningbox).click(function() {
			usePerson(existingPerson);
		});
		
		$('a.viewperson', warningbox).click(function() {
			viewPerson(existingPerson);
		});
		
		var existingPerson = null;
		
		var form = element.find('form');
		options.customValidation = $.extend({
					errorPlacement: function(error, element) {
						if(element.parent().find(".errorHolder").length == 0){
							error.appendTo(element.parent().parent().find(".errorHolder"));
						}
						else{
							error.appendTo(element.parent().find(".errorHolder"));
						}
					}
		}, options.customValidation);
		
		form.validate(options.customValidation);
				
		form.keyup(function() {
			warningbox.hide();
		});
		
		$(form[0].company).svCompanyAutocomplete();
		if (options.disableOrgSelector)
			$(form[0].company).attr('disabled', 'disabled');
			
		var usePerson = function(person) {
			var contId = parseInt(person.id);
			var contFullName = person.firstname + ' ' + person.surname;
			if (options.onSuccess(contId, contFullName)) {
				element.dialog("close");
				form.each(function(){this.reset()});
			}
		};
		
		var viewPerson = function(person) {
			location.href = 'contactmanager_person.asp?contId=' + person.id;
		};
			
		var submitForm = function(e) {
			if (form.valid()) {
				if (saveButton.html() != 'saving...') {
					saveButton.html('saving...');
					var url = form.attr('action');
					var data = form.serialize();
					
					var formUpdateComplete = function() { saveButton.html('save'); };
					
					var formUpdateSucces = function(response, textStatus) {
						if (response.success) {
							usePerson(response.data);
						}
						else {
							if (response.reason == RTN_EMAILADDRESSEXISTS) {
								introbox.hide();
								warningbox.show();
								existingPerson = response.existingContact;
							}
							else {
								alert("There was an unexpected problem while saving. Please try again.");
							}
						}
					};
					
					var formUpdateError = function(XMLHttpRequest, textStatus, errorThrown) {
						alert('There was a problem while saving. Please try again.');
					};
					if (options.beforeSubmit(form) == true) {
						$.ajax({
							complete: formUpdateComplete,
							data: data,
							dataType: 'json',
							error: formUpdateError,
							success: formUpdateSucces,
							type:'POST',
							url: url});
					}
					else {
						saveButton.html('save');
					}
				}
			}
		};
		
		var saveButton = $('a.save', element);
		saveButton.click(function() {
			submitForm();
			return false;
		});
		
		$('a.cancel', element).click(function() {
			element.dialog("close");
			return false;
		});
				
		var theDialog = element.dialog({
			autoOpen: false,
			height:270,
			modal: true, 
			overlay: { 
				opacity: 0.5, 
				background: "black" 
			},
			width:900,
			open: function() {
				introbox.show();
				warningbox.hide();
			}
		});		   
	
		$.extend(theDialog, {
			doSubmit: function() {
				submitForm();
			},
			populateForm: function(items) {
				for (var itemName in items) {
					form[0][itemName].value = items[itemName];
				}
				if (form[0]['company'].value != '') {
					$(form[0]['company']).addClass('company_selected');
				}
			}
		});
	};
})(jQuery);
(function($) {
	$.fn.svOrganisationPersonManager = function(options) {
		options = $.extend({
			onSuccess:function() {}
		}, options);
		
		return new $.OrganisationPersonManager(this, options);
	};
	
	$.OrganisationPersonManager = function(element, options) {
		var control = element;
		
		var form = control.find('form')[0];
		
		var autocomplete = control.find('input.addPerson').svPersonAutocomplete();
		
		var company_dialog = $('#createpersonatorganisationmodal');
		company_dialog.svCreatePersonModal({
			onSuccess:function(contId, contName) {
				addPersonToOrganisation(contId);
				return true;
			},
			disableOrgSelector: true
		});
		
		var addButton = control.find('a.addPerson').click(function() {
			var contId = parseInt(form.contId.value);
			var contName = form.person_name.value;
			if (contId <= 0 || isNaN(contId)) {
				var firstname = contName.indexOf(" ") != -1 ? contName.substring(0, contName.indexOf(" ")) : contName;
				var surname = contName.indexOf(" ") != -1 ? contName.substring(contName.indexOf(" ") + 1) : '';
				company_dialog.populateForm({firstname: firstname, surname: surname, compId: form.compId.value, company: form.company.value});
				company_dialog.dialog('open');	
			}
			else {
				addPersonToOrganisation(contId);
			}
			return false;
		});
		
		var addPersonToOrganisation = function(contId) {
			submitForm('add', contId);
		};
		
		var removePerson = function() {
			var contId = $(this).parents('tr').attr('id').replace(/person_/, '');
			submitForm('remove', contId);
			return false;
		};
		
		var submitForm = function(updateFunction, contId) {
			var url = $(form).attr('action');
			form.contId.value = contId;
			var data = $(form).serialize();
			data += "&updateFunction=" + updateFunction;
			$.ajax({
				complete: formUpdateComplete,
				data: data,
				dataType: 'html',
				error: formUpdateError,
				success: formUpdateSuccess,
				type:'POST',
				url: url
			});
		};
		
		var formUpdateError = function(XMLHttpRequest, textStatus, errorThrown) {
			alert('There was a problem while saving. Please try again.');
		};
		
		var formUpdateSuccess = function(data, textStatus) {			
			if ($(data).html() != null)
				options.onSuccess();
			else
				formUpdateError(null, textStatus, null);
		};
		
		var formUpdateComplete = function() {
		}
		
		control.find('a.remove').click(removePerson);
		
		$('tr', control).hover(
			function() {
				$('a.remove', $(this)).show();
			},
			function() {
				$('a.remove', $(this)).hide();
			}
		);
	};
})(jQuery);



		
(function($) {
	$.fn.svContactAddressManager = function() {
		
		return this.each(function() {
			var control = $(this);
			
			var radio = control.find(':radio').change(function() {
				controlFormAccess();
			});
			
			function controlFormAccess() {
				
				var disabledStatus;
				radio.filter(':checked').val() == 0 || radio.length <= 0 ? disabledStatus = false : disabledStatus = true;
				control.find(':input.address, select[name=countryId]').attr('disabled', disabledStatus);
			}
			
			controlFormAccess();
		});
	}
})(jQuery);



		
(function($) {
	$.fn.svMasterSelectBox = function(options) {
			
		//default settings
		var settings = {
				idMasterSelect: '',
				idSlaveSelect: '',
				idOptionHolder: ''
		}; //note: ids cannot be defaulted and must be specified in the call
		//note: classes should be set for hidden options as 'pid' & parent.id
	
		//use specified settings if available
		if(options) {
			jQuery.extend(settings, options);
		};
		
		var masterSelect = $('#' + settings.idMasterSelect);
		var slaveSelect = $('#' + settings.idSlaveSelect);
		var hiddenSelect = $('#' + settings.idOptionHolder);
		hiddenSelect.hide();
		
		var setSlaveOptions = function() {
			var masterValue = masterSelect.find('option:selected').attr("value");
			var slaveValue = slaveSelect.find('option:selected').attr("value");
			slaveSelect.find('option[class!=empty]').remove();

			//get the selected master values
			masterSelect.find('option:selected').each(function () {
				//get slave options
				optionsToShow = $('#' + settings.idOptionHolder + '> option[class=pid' + masterValue + ']');
				//add the slave options
				optionsToShow.clone().appendTo(slaveSelect);
			});		
		};
		
		masterSelect.change(function(){
			setSlaveOptions();
			slaveSelect.selectOptions('', true);
		});
		
		this.bind('setSlaveOptions', function() {
			setSlaveOptions();
		});
		
		setSlaveOptions();
	};
})(jQuery);


(function($) {
	$.fn.svExpandingIconList = function(options) {
			
		//default settings
		var settings = {
				moreLinkId: 'more',
				lessLinkId: 'less',
				intTrimAfter: 6
		}; //note: ids cannot be defaulted and must be specified in the call
	
		//use specified settings if available
		if(options) {
			jQuery.extend(settings, options);
		};
		
		var iconList = $(this);
		var lessLink = $('#' + settings.lessLinkId).toggle();
	    var moreLink = $('#' + settings.moreLinkId);
		var trimAfterCount = settings.intTrimAfter;
		var iconListCount = $(this).children().length;
		var listItemsHidden = $(this).children().slice(trimAfterCount, iconListCount).toggle();
		if (listItemsHidden.length == 0) {
			moreLink.toggle();
		};
		moreLink.click(function(){
			toggleMoreIcons();
		});
		lessLink.click(function(){
			toggleMoreIcons();
		});
		
		function toggleMoreIcons(){
			listItemsHidden.toggle();
			moreLink.toggle();
			lessLink.toggle();
		};

	};
})(jQuery);


(function($) {
	$.fn.svDocumentTagAutoComplete = function() {
		var TAG_ID = 0;
		var TAG_TEXT = 1;
		var TAG_TYPEID = 2;
		var TAG_TYPENAME = 3;
		var TAG_ITEMID = 4;
		
		return this.each(function() {
			var control = $(this);
			
			control.autocomplete('docrep_documenttagautocomplete.asp', {
				minChars: 2,
				multiple:true,
				selectFirst:false,
				formatItem: function(data, i, total, value) {
					var item = '';
					
					item += "<span class=\"" + data[TAG_TYPENAME] + "_tag\">";
					item += data[TAG_TEXT];
					item += "</span>";

					return item;
				},
				formatResult: function(data, i, total, value) {
					var item = data[TAG_TEXT];
					return item;
				}
			});
		});
	}
})(jQuery);



		
(function($) {
    $.fn.productImageManager = function(options) {
        var defaults = {
            uploadURL: '',
            updateURL: '',
            removeHandle: '',
            container: '',
            params: {},
            asyncDelete: true,
            fadeSpeed: 'slow',
            allowMultiple: true
        };

        var options = $.extend(defaults, options);
        return new $.productImageManager(this, options);
    },
	$.productImageManager = function(element, options) {
	    element.upload({
	        name: 'file1',
	        method: 'post',
	        action: options.uploadURL,
	        onSubmit: function() {

	        },
	        onComplete: function(data) {
	            var new_item = $($(data).html());
	            new_item.css({ display: 'none' });
	            if (!options.allowMultiple) {
	                $(options.container).empty();
	            }
	            $(options.container).append(new_item);
	            new_item.fadeIn(options.fadeSpeed);
	        },
	        params: options.params
	    });

	    var removeImage = function() {

	    };

	    $(options.removeHandle, $(options.container)[0]).livequery('click', function() {
	        var imageId = $(this).attr('id').replace(/remove_image_/, '');
	        if (options.asyncDelete) {
	            $.post(options.updateURL, $.extend({ imageId: imageId, action: 'REMOVE', asynch: 'true' }, options.params));
	        }
	        $('#image_' + imageId).fadeOut(options.fadeSpeed, function() { $(this).remove(); });
	        return false;
	    });
	}
})(jQuery);

	

(function($) {
	$.fn.svRelatedSelectBoxes = function(options) {
		options = $.extend({
			slave:'',
			url:''
		}, options);
		
		return new $.RelatedSelectBoxes(this, options);
	};
	
	$.RelatedSelectBoxes = function(element, options) {
		var self = this;
		
		var master = $(element);
		var slave = $(options.slave);
		
		master.change(function() {
			slave.removeOption(/./);
			slave.ajaxAddOption(options.url, {parentId:$(this).selectedValues()[0]});
		});
	};
})(jQuery);

(function($) {
    $.fn.svProductAutocomplete = function(options) {
        var opts = $.extend({}, $.fn.svProductAutocomplete.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            var showProductLookup = function() {
                $('<div />').svProductLookupModal({ query: $element.val(), extraParams: opts.extraParams, onSelect: function(id, code, name) { $element.val(name); $element.trigger('setResult', [id, code, name]); } });
            };

            if (opts.allowLookup) {
                $element.after($('<input type=\"button\" value=\"Lookup\" />').click(showProductLookup));
            }

            opts.formatResult = function(data, i, total, value) {
                var name = '';
                if (opts.includeCodeInResult)
                    name += '(' + data[PRODUCT_CODE] + ') ';
                name += data[PRODUCT_NAME];
                return name;
            };

            $element.svAutocomplete(opts);
        });
    };

    var PRODUCT_ID = 0;
    var PRODUCT_CODE = 1;
    var PRODUCT_NAME = 2;

    $.fn.svProductAutocomplete.defaults = {
        url: 'productmanager_productAutocomplete.asp',
        result: function(e, data, formatted) {
            var id = data[PRODUCT_ID];
            var code = data[PRODUCT_CODE];
            var name = data[PRODUCT_NAME];
            $(e.target).trigger('setResult', [id, code, name]);
        },
        onchange: function(e) {
            $(e.target).trigger('setResult', [0, '', '']);
        },
        formatItem: function(data, i, total, value) {
            var item = '';
            var id = data[PRODUCT_ID];
            var code = data[PRODUCT_CODE];
            var name = data[PRODUCT_NAME];
            item += '<span class=\'name\'>'
            item += '(' + code + ') ' + name;
            item += '</span>';

            return item;
        },
        includeCodeInResult: false,
        allowLookup: true,
        filters: function() { return ''; },
        extraParams: { params: function() { return 'eggs'; } }
    };
})(jQuery);

(function($) {
	$.fn.svBOMEditor = function(options) {
		options = $.extend({
		}, options);
		
		return new $.BOMEditor(this, options);
	};
	
	$.BOMEditor = function(element, options) {	
		var form = $('#productbomsection-edit').find('form')[0];
		
		var component = $('#component_text').svProductAutocomplete({
			extraParams: {exclude: form.prodId.value}
		});
		component.data('id', 0);
		
		var quantity = $('input[name=quantity]', element);
			
		var deleteRow = function() {
			tr = $(this).parents('tr');
			if (tr.data('new') == 'true')
				tr.remove();
			else {
				var qtyInput = $('input[name^=quantity]', tr);
				var qty = qtyInput.val();
				qtyInput.val('0');
				tr.data('qty', qty).hide();
			}
			return false;
		};
		
		var appendRow = function(id, code, name, qty) {
			var row = createRow(id, code, name, qty);
			row.data('new', 'true');
			$('tr.newcomprow', element).before(row);
		};
		
		var createRow =function(id, code, name, qty) {
			var inputColumn = createQtyInput(id, qty);
			var nameColumn = createNameColumn(id, name);
			var codeColumn = createCodeColumn(code);
			var removeColumn = createRemoveColumn(id);
			
			var row = $('<tr></tr>').append(codeColumn).append(nameColumn).append(inputColumn).append(removeColumn);
			row.addClass('bomRow');
			return row;
		};
		
		var createQtyInput = function(id, qty) {
			var col = $('<td><input class=\"quantity\" name=\"quantity_' + id + '\" value=\"' + qty + '\" /></td>');
			return col;
		};
		
		var createNameColumn = function(id, name) {
			var col = $('<td><a href=\"productmanager_product.asp?prodId=' + id + '\" class=\"product\ {id: ' + id + ', name: \'' + name + '\'}\">' + name + '</a></td>');
			return col;
		};
		
		var createCodeColumn = function(code) {
			var col = $('<td>' + code + '</td>');
			return col;
		};
		
		var createRemoveColumn = function(id) {
			var link = $('<a href=\"#\">remove</a>');
			link.click(deleteRow);
			var col = $('<td></td>').append(link);
			return col;
		};
		
		var resetEditor = function() {
			$('tr.bomRow').each(function() {
				var tr = $(this);
				if (tr.data('new') == 'true')
					tr.remove();
				
				if (tr.data('qty') > 0) {
					$('input[name^=quantity]', tr).val(tr.data('qty'));
					tr.removeData('qty');
					tr.show();
				}
			});
		};
		
		$('.addnewcomponent', element).click(function() {
			var id = component.data('id');
			var code = component.data('code');
			var name = component.data('name');
			var qty = quantity.val();
			if (id > 0 && qty > 0) {
				appendRow(id, code, name, qty);
				component.trigger('reset');
				quantity.val('');
			}
			return false;
		});
		
		$('a.remove', element).click(deleteRow);
		
		element.bind('reset', function() {
			resetEditor();
		});
	};
})(jQuery);

$(function(){
	window.onbeforeunload = function() {
		if ($('body').data('openEditors') > 0) {
			return 'You have editors open which have not been saved. Any changes you have made may be lost.';
		}
	};
});
(function($) {
	$.fn.svEntitylistQuicklinks = function(options) {
			
		//default options
		var settings = {
				idDeleteEntityListModal: '',				
				idEditEntityListModal: '',
				idQuickLinks: ''
		}; 	
		//use specified options if available
		if(options) {
			jQuery.extend(settings, options);
		};
		
		return new $.EntitylistQuicklinks(this, options);
	};
	
	$.EntitylistQuicklinks = function(element, options) {
		var deletelist_dialog = $('#' + options.idDeleteEntityListModal);
		
		deletelist_dialog.dialog({
				modal: true,
				autoOpen: false,
				overlay: {opacity: 0.5, background: "black"},
				width: 300,
				height: 120
		});
		
		var editlist_dialog = $('#' + options.idEditEntityListModal);
			   
		editlist_dialog.dialog({
				modal: true,
				autoOpen: false,
				overlay: {opacity: 0.5, background: "black"},
				width: 300,
				height: 250
		});
		
		var listId = $(element).find('a.deleteList').attr('id').replace(/deleteList_/,'');
		
		var deletebuttonsdiv = deletelist_dialog.find('div[id^=redirectURL_]');
		var redirectURL = $(deletebuttonsdiv).attr('id').replace(/redirectURL_/, '');
			   
	     $(element).find('a[id^=deleteList_]').click(function(){
			deletelist_dialog.dialog('open');
			deleteButton.attr("href", $(this).attr("href"));
			return false;
		});
	
		 $(element).find('a[id^=editList_]').click(function(){
			editlist_dialog.dialog('open');
			saveButton.attr("href", $(this).attr("href"));
			return false;
		});
		
		var cancelDeleteLink = deletelist_dialog.find('a.cancel').click(function () {
			deletelist_dialog.dialog('close');
			return false;
		});
		var cancelEditLink = editlist_dialog.find('a.cancel').click(function () {
			editlist_dialog.dialog('close');
			return false;
		});
		   
		var deleteButton = deletelist_dialog.find('a#deleteListButton').click(function () {
			var url = $(this).attr("href");
			if (deleteButton.html() != 'deleting...') {
				deleteList(url);
			};
			return false;
		});
		
		var saveButton = editlist_dialog.find('a.save').click(function () {
			if (saveButton.html() != 'saving...') {
				submitForm();
			};
			return false;
		});
		
		var deleteList  = function(strUrl){
			deleteButton.html('deleting...');
				$.ajax({
					data: {
						listId:		listId
					},
					dataType: 'json',
					error: function() { 
						alert('There was a problem while deleting. Please try again.');
						deleteButton.html('delete');
					},
					success: function() {
						deletelist_dialog.dialog('close');
						window.location = redirectURL;
					},
					type:'POST',
					url: strUrl
				});
		}
		
		var form = editlist_dialog.find('form');
		
		var isNameUnique = function(value, element, param) {
			var completed = false;
			var isUnique = false;
			
			$.ajax({
				url: 'entitylist_json_checknameisunique.asp?listname=' + form[0].Name.value + '&typeId=' + form[0].typeId.value + '&statusId=' + form[0].statusId.value + '&listId=' + form[0].listId.value,
				success: function(data, textStatus) {isUnique = data;},
				complete: function() {completed = true},
				dataType: 'json',
				async: false
			});
		
			return (isUnique || value == "");
		};
		
		var setupEditForm = function() {
				form.submit(function() {
					submitForm();
					return false;
				});
				form.validate({
						errorPlacement: function(error, element) {
							element.parent().find(".errorHolder").text('');
							error.appendTo(element.parent().find(".errorHolder"));
						},
						rules:{
							Name: {
								required: true,
								listname: true
							}
						},
						messages: {
							Name: {
								required: "Please enter a name for this list."
							}
						}		
				});
		};
		
		$.validator.addMethod("listname", isNameUnique, "That list name is already in use.");
		
		setupEditForm();
		
		var submitForm = function() {
						if (form.valid()) {
							saveButton.html('saving...');
							var saveUrl = form.attr('action');
							var data = form.serialize();
							$.ajax({
								data: data,
								dataType: 'json',
								error: function() { 
									alert('There was a problem while saving. Please try again.');
									saveButton.html('save');
								},
								success: function() {
									window.location.reload();
								},
								type:'POST',
								url: saveUrl
							});
							return false;
						};
		};


	};
})(jQuery);
(function($) {
    $.fn.svGoodsInModal = function(options) {
        options = $.extend({
            onSuccess: function() { },
            allowProductCreation: true,
            allowContractCreation: true
        }, options);

        return new $.GoodsInModal(this, options);
    };

    $.GoodsInModal = function(element, options) {
        element.svManualGoodsMovementModal(options);
    };
})(jQuery);

(function($) {
	$.fn.svGoodsOutModal = function(options) {
		options = $.extend({
			onSuccess:function() {}
		}, options);
		
		return new $.GoodsOutModal(this, options);
	};
	
	$.GoodsOutModal = function(element, options) {
		element.svManualGoodsMovementModal(options);
	};
})(jQuery);

(function($) {
	var locationsAreDifferent = function(value, element, param) {
		var form = element.form;
		return !((form.warehouseId.value == form.toWarehouseId.value) 
				&&
				(form.rack.value == form.toRack.value)
				&&
				(form.row.value == form.toRow.value)
				&&
				(form.bin.value == form.toBin.value));
	};
		
	$.validator.addMethod("locationMustNotBeIdentical", locationsAreDifferent, "To location must be different to from location.");
		
	$.fn.svStockTransferModal = function(options) {
		options = $.extend({
			onSuccess:function() {},
			customValidation:{
				rules: {
					product: {
						required: true,
						product: true
					},
					quantity: {
						required: true,
						min:0
					},
					toWarehouseId: {
						locationMustNotBeIdentical: true
					},
					toRack: {
						locationMustNotBeIdentical: true
					},
					toRow: {
						locationMustNotBeIdentical: true
					},
					toBin: {
						locationMustNotBeIdentical: true
					}
				},
				groups: {
					location:"toWarehouseId toRack toRow toBin"
				},
				errorPlacement: function(error, element) {
					if (element.attr('name') == 'toWarehouseId' || element.attr('name') == 'toRack' || element.attr('name') == 'toRow' || element.attr('name') == 'toBin') 
						error.appendTo($('.locationValidation'));
					else
						error.insertAfter(element);
				}
			}
		}, options);
		
		return new $.StockTransferModal(this, options);
	};
	
	$.StockTransferModal = function(element, options) {
		element.svManualGoodsMovementModal(options);
	};
})(jQuery);

(function($) {
	$.fn.svReportOptions = function(options) {
		options = $.extend({
		}, options);
		
		return new $.ReportOptions(this, options);
	};
	
	$.ReportOptions = function(element, options) {
		var optionForm = $('form', element);
		var toggleForm = function() {
			
			optionForm.toggle();
			optionForm[0].reset();
			optionButton.toggleClass('options_on');
			return false;
		};
		
		var optionButton = $('a.options', element).click(toggleForm);
		var cancelButton = $('a.cancel', element).click(toggleForm);
		
	};
})(jQuery);

(function($) {
		  
    $.fn.svProductHeader = function(options) {
        var isProductCodeUnique = function(value, element, param) {
            var form = element.form;
            var isUnique = false;

            $.ajax({
                url: 'productmanager_json_checkproductcodeisunique.asp?prodId=' + form.prodId.value + '&code=' + form.code.value,
                success: function(data, textStatus) { isUnique = data; },
                complete: function() { },
                dataType: 'json',
                async: false
            });

            return isUnique;
        };

        $.validator.addMethod("productCodeUnique", isProductCodeUnique, "Product Codes must be unique.");

        options = $.extend({
            customValidation: {
                rules: {
                    name: {
                        required: true
                    },
                    code: {
                        productCodeUnique: true
                    }
                }
            }
        }, options);

        return new $.ProductHeader(this, options);
    };

    $.ProductHeader = function(element, options) {
        var $element = $(element);
        
        function setupForm() {
            $('#' + $element.attr('id') + '-edit').svProductHeaderForm();
        }

        var onSuccess = options.onSuccess;
        
        options.onSuccess = function() {
            setupForm();
            onSuccess();
        };
		
		options.beforeSubmit = function(){
				var compId = $('#compId').attr('value');
				var compName = $('#supplierId').attr('value');
	
				if (compId == '0' && compName != '') {
					var quickcompform = company_dialog.find('form');
					quickcompform.find('input.name').attr('value', compName);
					company_dialog.dialog("open");
					return false;
				}
				else {
					return true;
				}
		};

        setupForm();

        var productdetailsection = $element.svEditableSection(options);
		
		var company_dialog = $('#createcompanymodal');
		company_dialog.svCreateCompanyModal({
			onSuccess: function(compId, compName) {
				if (compId > 0) {
					$("#compId").attr('value', compId);
					$("#supplierId").attr('value', compName);
					$("#supplierId").addClass('company_selected');
				}
				company_dialog.dialog("close");
				productdetailsection.submit();
				return true;
			}
		});
		
    };
})(jQuery);

(function($) {
    var hadFirstSubmit = false;
    var productSelected = function(value, element, param) {
        return element.form.productId.value > 0 || !hadFirstSubmit;
    };

    $.validator.addMethod("product", productSelected, "Unknown product.");
    $.validator.addMethod("ddmmyyyy", function(value, element) {
        return value.match(/^\d\d?\/\d\d?\/\d\d\d\d$/);
    },
    "Please enter a date in the format dd/mm/yyyy");

    $.fn.svManualGoodsMovementModal = function(options) {
        options = $.extend({
            allowProductCreation: false,
            allowContractCreation: false,
            onSuccess: function() { },
            contractModal: $('#addeditcontractmodal'),
            productModal: $('#addproductmodal')
        }, options);

        return new $.ManualGoodsMovementModal(this, options);
    };

    $.ManualGoodsMovementModal = function(element, options) {
        var self = $(this);

        var form = $('form', $(element));

        var lotNoRow = $('div.lotNo', element).hide();
        var expiryDateRow = $('div.expiryDate', element).hide();
        var bbeRow = $('div.BBE', element).hide();

        var contractAutocomplete = $('input.contractAutocomplete', element).svContractAutocomplete();
        var projectAutocomplete = $('input.projectAutocomplete', element).svProjectAutocomplete({ rootContractSelector: contractAutocomplete });

        options.customValidation = $.extend({
            rules: {
                product: {
                    required: true,
                    product: !options.allowProductCreation
                },
                quantity: {
                    required: true,
                    min: 0
                },
                receiptdate: {
                    required: true,
                    ddmmyyyy: true
                }
            }
        }, options.customValidation);

        form.validate(options.customValidation);

        var statusBox = $('.statusrow .status', element);

        $('input.datepicker', element).datepicker({
            dateFormat: 'dd/mm/yy'
        });

        form.keyup(function() {
            updateStatusBox('Ready');
        });

        var updateStatusBox = function(text) {
            statusBox.html(text);
            theDialog.dialog('option', 'position', 'center');
        };

        var productBox = $('input.productAutocomplete', form).svProductAutocomplete({
            onSet: function(id, code, name) {
                if (id > 0) {
                    setContractProjectForProduct(id);
                }
            },
            includeCodeInResult: true
        });

        var theDialog = element.dialog({
            autoOpen: false,
            modal: true,
            overlay: {
                opacity: 0.5,
                background: "black"
            },
            height: 540,
            width: 500
        });

        var error = function(data, textStatus) {
            statusBox.addClass('error');
            if (data.reason)
                updateStatusBox(data.reason);
            else
                updateStatusBox('Unexpected error. Please try again.');
        };

        var success = function(data, textStatus) {
            if (data.success) {
                updateStatusBox(data.reason);
                var warehouseId = form[0].warehouseId.value;
                resetForm(warehouseId);
                options.onSuccess();
            }
            else
                error(data, textStatus);
        };

        var complete = function() {
            processButton.html('process');
        };

        function setContractProjectForProduct(productId) {
            $.ajax({
                url: 'contracts_json_getProjectForProduct.asp',
                dataType: 'json',
                data: { productId: productId },
                success: function(data, textStatus) {
                    if (data.id > 0) {
                        var name = '(' + data.longcode + ') ' + data.longname;
                        projectAutocomplete.trigger('setResult', [data.id, data.code, data.name, false]);
                        projectAutocomplete.val(name)
                    }
                }
            });
        }


        var submitForm = function() {
            hadFirstSubmit = true;
            if (form.valid() && processButton.html() != 'processing...' && productExists() && contractsExist() && projectsExist()) {
                processButton.html('processing...');
                $.ajax({
                    cache: false,
                    complete: complete,
                    data: form.serialize(),
                    dataType: 'json',
                    error: error,
                    success: success,
                    type: 'POST',
                    url: form.attr('action')
                });
            }
            return false;
        };

        function productExists() {
            var doesProductExists = true;
            if (unknownItemEntered(productBox)) {
                doesProductExists = false;
                if (options.allowProductCreation) {
                    options.productModal.trigger('open', [productBox.val(), function(data, textStatus) {
                        productBox.val(data.name);
                        productBox.trigger('setResult', [data.id, data.code, data.name]);
                        submitForm();
                    } ]);
                }
            }
            return doesProductExists;
        }

        function contractsExist() {
            var allContractsKnown = true;
            $('input.contractAutocomplete', element).each(function() {
                var $input = $(this);
                if (unknownItemEntered($input)) {
                    $input.css('border', '1px solid #aaa');
                    if (options.allowContractCreation) {
                        options.contractModal.trigger('openForNewContract', [$input.val(), function(data, textStatus) {
                            $input.val(data.name);
                            $input.trigger('setResult', [data.id, data.code, data.name]);
                            submitForm();
                        } ]);
                    }
                    else {
                        alert('The contract you have entered cannot be found. Please re-enter and try again.');
                    }
                    allContractsKnown = false;
                    return false;
                }
            });
            return allContractsKnown;
        }

        function projectsExist() {
            var allProjectsKnown = true;
            $('input.projectAutocomplete', element).each(function() {
                var $input = $(this);
                if (unknownItemEntered($input)) {
                    allProjectsKnown = false;
                    if (options.allowContractCreation) {
                        options.contractModal.trigger('openForNewProject', [$input.val(), $('input.contractAutocomplete', element).data('id'), function(data, textStatus) {
                            $input.val(data.name);
                            $input.trigger('setResult', [data.id, data.code, data.name]);
                            submitForm();
                        } ]);
                    }
                }
            });
            return allProjectsKnown;
        }

        function unknownItemEntered(element) {
            return element.val() != '' && (element.data('id') == 0 || element.data('id') == '');
        }



        var processButton = $('a.process', element[0]).click(function() {
            submitForm();
            return false;
        });

        $('a.cancel', element).click(function() {
            theDialog.dialog('close');
            return false;
        });

        var setWarehouse = function(warehouseId) {
            if (warehouseId > 0) {
                form[0].warehouseId.value = warehouseId;
            }
        };

        var resetForm = function(warehouseId) {
            form[0].reset();
            productBox.trigger('reset');
            $('input.contractAutocomplete', element).trigger('reset');
            $('input.projectAutocomplete', element).trigger('reset');
            hadFirstSubmit = false;
            setWarehouse(warehouseId);
        }

        var showHideExtendedSpecs = function(data, textStatus) {

            if (data && data.hasLotNo) {
                lotNoRow.show();
                $('input', lotNoRow).rules('add', { required: true });
            }
            else {
                lotNoRow.hide();
                $('input', lotNoRow).rules('remove');
            }

            if (data && data.hasExpiryDate) {
                expiryDateRow.show();
                $('input', expiryDateRow).rules('add', { required: true, date: true });
            }
            else {
                expiryDateRow.hide();
                $('input', expiryDateRow).rules('remove');
            }


            if (data && data.hasBBE) {
                bbeRow.show();
                $('input', bbeRow).rules('add', { required: true, date: true });
            }
            else {
                bbeRow.hide();
                $('input', bbeRow).rules('remove');
            }
        };

        var getProductDetails = function(id) {
            $.ajax({
                cache: false,
                data: { prodId: id },
                dataType: 'json',
                error: function() { },
                complete: function() { },
                success: showHideExtendedSpecs,
                type: 'POST',
                url: 'productmanager_json_getProductDetails.asp'
            });
        };

        element.bind("openForWarehouse", function(event, warehouseId) {
            resetForm(warehouseId);
            theDialog.dialog('open');
        });
        element.bind("openForAllWarehouses", function(event) {
            resetForm(0);
            theDialog.dialog('open');
        });
    };
})(jQuery);

(function($) {
	$.fn.svDataRow = function(options) {
		options = $.extend({
		}, options);
		
		return this.each(function() {
			element = $(this);
			$('ul.options', element).hide();
			$('ul.options', element).click(function() { return false; });
			element.hover(
				function() {
					$('ul.options', $(this)).show();
				},
				function() {
					$('ul.options', $(this)).hide();
				}
			);
				
		});
	};
})(jQuery);

(function($) {
    $.fn.svEditContractModal = function(options) {
        var opts = $.extend({}, $.fn.svEditContractModal.defaults, options);

        return this.each(function() {
            var $element = $(this);
            var handlersInitialized = false;
            var form;
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            function setup() {
                if (!handlersInitialized) {
                    form = $('form', $element);

                    form.validate({
                        rules: {
                            code: {
                                uniqueShortCode: true
                            }
                        }
                    });

                    $('input.organisation').svCompanyAutocomplete({
                        fieldName: 'primaryPartyId'
                    });

                    var savebutton = $('a.save', $element);
                    function submitForm() {
                        var success = function(data, textStatus) {
                            theDialog.dialog('close');
                            opts.onSuccess(data, textStatus);
                        };
                        var error = function() { alert('There was a problem saving the contract. Please try again.'); };
                        var complete = function() { savebutton.html('save'); };

                        if (form.valid() && savebutton.html() == 'save') {
                            savebutton.html('saving...');
                            $.ajax({
                                url: form.attr('action'),
                                data: form.serialize(),
                                dataType: 'json',
                                success: success,
                                error: error,
                                complete: complete,
                                type: 'POST'
                            });
                        }
                        return false;
                    }
                    savebutton.click(submitForm);
                    form.submit(submitForm);

                    $('a.cancel', $element).click(function() { theDialog.dialog('close'); return false; });

                    handlersInitialized = true;
                }
            }

            var isShortCodeUniqueInContract = function(value, element, param) {
                var isUnique = true;

                if (value != '') {
                    $.ajax({
                        url: 'contracts_json_checkshortcodeisuniqueforcontract.asp?contractId=' + (element.form.parentContractId.value > 0 ? element.form.parentContractId.value : element.form.contractId.value) + '&shortcode=' + value,
                        success: function(data, textStatus) { isUnique = data; },
                        dataType: 'json',
                        async: false
                    });
                }

                return isUnique;
            };

            $.validator.addMethod('uniqueShortCode', isShortCodeUniqueInContract, 'That short code is already in use. Please try another.');

            var theDialog = $element.dialog({
                autoOpen: false,
                modal: true,
                overlay: {
                    opacity: 0.5,
                    background: "black"
                },
                height: 250,
                width: 640,
                open: function() { setup(); form.get(0).reset(); }
            });

            $element.bind("openForContract", function(event, contractId, initialOrganisation) {
                $('.sectioneditor', $element).show();
                $('.toolbox', $element).hide();
                theDialog.dialog('open');
            });

            $element.bind("openForNewContract", function(e, nameOrCode, callback) {
                opts.onSuccess = callback;

                getModalForguessedPartiesAndContract(nameOrCode, null, function() {
                    $('.sectioneditor', $element).show();
                    $('.toolbox', $element).hide();
                    theDialog.dialog('open');
                });
            });

            $element.bind("openForNewProject", function(e, nameOrCode, contractId, callback) {
                opts.onSuccess = callback;
                getModalForguessedPartiesAndContract(nameOrCode, contractId, function() {
                    $('.sectioneditor', $element).show();
                    $('.toolbox', $element).hide();
                    theDialog.dialog('open');
                });

            });

            function getModalForguessedPartiesAndContract(nameOrCode, rootContractId, callback) {
                $.ajax({
                    url: 'contracts_ModalForGuessedPartiesAndContract.asp',
                    data: { nameOrCode: nameOrCode, rootContractId: rootContractId },
                    dataType: 'html',
                    success: function(data, textStatus) {
                        var $data = $(data);
                        var contractId = parseInt($('input[name=contractId]', $data).val());
                        if (contractId == 0 || isNaN(contractId)) {
                            handlersInitialized = false;
                            $('#contractmodal-edit-body', $element).html($('#contractmodal-edit-body', $(data)).html());
                            callback();
                        }
                        else {
                            var contractName = $('input[name=name]', $data).val();
                            theDialog.dialog('close');
                            opts.onSuccess({ id: contractId, name: contractName });
                        }
                    }

                });
            }
        });
    };

    $.fn.svEditContractModal.defaults = {
        onSuccess: function() { }
    };
})(jQuery);

(function($) {
    $.fn.svOrderLineFieldset = function(element, options) {
        options = $.extend({
            onSuccess: function() { },
            orderId: null,
            rootContractSelect: '',
            contractSelect: '',
            key: null,
            url: '',
            refreshUrl: '',
            action: ''
        }, options);

        return new $.OrderLineFieldset(element, options);
    };

    $.OrderLineFieldset = function(element, options) {
        var self = $(element);

        var productSelect = $('input.product', element)
        productSelect.svProductAutocomplete({
            extraParams: {
                clearfilters: true,
                contract: function() {
                    return $(options.contractSelect).val();
                }, rootContract: function() {
                    return $(options.rootContractSelect).val();
                }
            }
        });

        function outputOrderLines(data, textStatus) {
            $('li.orderlines', element).html(data);
            $('a.delete_line', element).click(function() {
                var data = $(this).metadata();
                $.ajax({
                    url: options.url,
                    complete: function() { },
                    data: { productId: data.productId, orderId: options.orderId, key: data.key, action: 'DELETE', contractId: function() { return $(options.contractSelect).val(); }, typeId: function() { return $(options.typeSelect).val(); } },
                    dataType: 'html',
                    type: 'POST',
                    success: outputOrderLines,
                    error: function() { }
                });
                return false;
            });
            resetForm();
        }

        var addButton = $('#addline').click(function() {
            function validQuantity(qty) {
                return (!isNaN(qty));
            }

            function validProduct(productId) {
                return (productId > 0);
            }

            function complete(data, textStatus) {
                addButton.html('Add').attr('disabled', '');
                self.find('.errorHolder').html("");
            }

            function error(data, textStatus) {
            }

            var qty = $('input.quantity', element).val();
            var productId = productSelect.data('id');
            if (validQuantity(qty) && validProduct(productId)) {
                addButton.html('Adding...').attr('disabled', 'disabled');
                $.ajax({
                    url: options.url,
                    complete: complete,
                    data: { productId: productId, quantity: qty, orderId: options.orderId, key: options.key, action: options.action, contractId: function() { return $(options.contractSelect).val(); }, typeId: function() { return $(options.typeSelect).val(); } },
                    dataType: 'html',
                    type: 'POST',
                    success: outputOrderLines,
                    error: error
                });
            }

            return false;
        });

        var resetForm = function() {
            $('input.quantity', element).val('').focus();
            productSelect.trigger('reset');
        };

        $(element).bind('refresh', function() {
            $.ajax({
                url: options.refreshUrl,
                data: { orderId: options.orderId, contractId: function() { return $(options.contractSelect).val(); }, typeId: function() { return $(options.typeSelect).val(); } },
                dataType: 'html',
                type: 'POST',
                success: outputOrderLines
            });
        });
    };
})(jQuery);

(function($) {
    var orderTypes = { MAILORDER: 1, DISTRIBUTION: 2 };
    $.fn.svOrderDispatchFieldset = function(options) {
        options = $.extend({
            orderType: orderTypes.DISTRIBUTION,
            orderlineFieldset: '',
            readonly: false
        }, options);

        return new $.OrderDispatchFieldset(this, options);
    };

    $.OrderDispatchFieldset = function(element, options) {
        var $element = $(element);
        options = $.metadata ? $.extend({}, options, $element.metadata()) : options;

        function setTabsAndBilling() {
            if (options.orderType == orderTypes.MAILORDER) {
                $('a.addDispatch', element).hide();
                $('a.deleteaddress', element).hide();
                tablistbutton.hide();
                $('.billing', element).show();
            }
            else {
                if (!options.readonly) {
                    $('a.deleteaddress', element).show();
                    $('a.addDispatch', element).show();
                }
                tablistbutton.show();
                $('.billing', element).hide();
            }
        }

        if (!options.readonly) {
            $('a.addDispatch', element).click(function() {
                if (options.orderType == orderTypes.DISTRIBUTION) {
                    saveCurrentAddress({ action: 'NEW' });
                    tablist.hide();
                    return false;
                }
            });

            $('a.deleteaddress', element).click(function() {
                if (options.orderType == orderTypes.DISTRIBUTION) {
                    saveCurrentAddress({ action: 'DELETE' });
                    return false;
                }
            });

            $(element).bind('setOrderType', function(obj, typeId) {
                options.orderType = typeId;
                setTabsAndBilling();
            });

            $('input[name=useDeliveryForBilling]', element).change(function() {
                if ($(this).attr('checked')) {
                    $('#billingAddress input, #billingAddress select', element).attr('disabled', true);
                }
                else {
                    $('#billingAddress input, #billingAddress select', element).attr('disabled', false);
                }
            });

            var personSelector = $('#name', element);
            personSelector.svPersonAutocomplete({
                fieldName: 'personId',
                onSet: function() {
                    var id = personSelector.data('id');
                    if (id > 0) {
                        $.ajax({
                            url: 'contactmanager_json_person.asp',
                            data: { contId: id },
                            dataType: 'json',
                            type: 'GET',
                            success: function(data, textStatus) {
                                organisationSelector.trigger('set', [data.compId, data.compname, true]);
                                $('#division', element).val(data.division);
                                $('#addressline1', element).val(data.addressline1);
                                if ($('input#addressline1').val().length > 0) { clearAddressError(addrFirstLine) };
                                $('#addressline2', element).val(data.addressline2);
                                $('#addressline3', element).val(data.addressline3);
                                $('#addressline4', element).val(data.addressline4);
                                $('#towncity', element).val(data.addresstowncity);
                                $('#county', element).val(data.addresscounty);
                                $('#postcode', element).val(data.addresspostcode);
                                $('#countryId', element).val(data.addresscountryid);
                                $('#personId', element).val(id);
                                $('#organisationId', element).val(data.compId);
                                $('#tel1', element).val(data.tel);
                                $('#mobile', element).val(data.mobile);
                            }
                        });
                    }
                }
            });

            var billingPersonSelector = $('#billingName', element);
            billingPersonSelector.svPersonAutocomplete({
                fieldName: 'billingPersonId',
                onSet: function() {
                    var id = billingPersonSelector.data('id');
                    if (id > 0) {
                        $.ajax({
                            url: 'contactmanager_json_person.asp',
                            data: { contId: id },
                            dataType: 'json',
                            type: 'GET',
                            success: function(data, textStatus) {
                                billingOrganisationSelector.trigger('set', [data.compId, data.compname, true]);
                                $('#billingDivision', element).val(data.division);
                                $('#billingAddressline1', element).val(data.addressline1);
                                $('#billingAddressline2', element).val(data.addressline2);
                                $('#billingAddressline3', element).val(data.addressline3);
                                $('#billingAddressline4', element).val(data.addressline4);
                                $('#billingTowncity', element).val(data.addresstowncity);
                                $('#billingCounty', element).val(data.addresscounty);
                                $('#billingPostcode', element).val(data.addresspostcode);
                                $('#billingCountryId', element).val(data.addresscountryid);
                                $('#billingPersonId', element).val(id);
                                $('#billingOrganisationId', element).val(data.compId);
                                $('#billingTel1', element).val(data.tel);
                                $('#billingMobile', element).val(data.mobile);
                            }
                        });
                    }
                }
            });

            var organisationSelector = $('#organisation', element);
            organisationSelector.svCompanyAutocomplete({
                fieldName: 'organisationId',
                onSet: function() {
                    var id = organisationSelector.data('id');
                    if (id > 0) {
                        $.ajax({
                            url: 'contactmanager_json_organisation.asp',
                            data: { compId: id },
                            dataType: 'json',
                            type: 'GET',
                            success: function(data, textStatus) {
                                $('#division', element).val(data.division);
                                $('#addressline1', element).val(data.addressline1);
                                if ($('input#addressline1').val().length > 0) { clearAddressError(addrFirstLine) };
                                $('#addressline2', element).val(data.addressline2);
                                $('#addressline3', element).val(data.addressline3);
                                $('#addressline4', element).val(data.addressline4);
                                $('#towncity', element).val(data.addresstowncity);
                                $('#county', element).val(data.addresscounty);
                                $('#postcode', element).val(data.addresspostcode);
                                $('#countryId', element).val(data.addresscountryid);
                                $('#organisationId', element).val(id);
                                $('#tel1', element).val(data.tel);
                                $('#tel2', element).val(data.tel2);
                            }
                        });
                    }

                }
            });

            var billingOrganisationSelector = $('#billingOrganisation', element);
            billingOrganisationSelector.svCompanyAutocomplete({
                fieldName: 'billingOrganisationId',
                onSet: function() {
                    var id = billingOrganisationSelector.data('id');
                    if (id > 0) {
                        $.ajax({
                            url: 'contactmanager_json_organisation.asp',
                            data: { compId: id },
                            dataType: 'json',
                            type: 'GET',
                            success: function(data, textStatus) {
                                $('#billingDivision', element).val(data.division);
                                $('#billingAddressline1', element).val(data.addressline1);
                                $('#billingAddressline2', element).val(data.addressline2);
                                $('#billingAddressline3', element).val(data.addressline3);
                                $('#billingAddressline4', element).val(data.addressline4);
                                $('#billingTowncity', element).val(data.addresstowncity);
                                $('#billingCounty', element).val(data.addresscounty);
                                $('#billingPostcode', element).val(data.addresspostcode);
                                $('#billingCountryId', element).val(data.addresscountryid);
                                $('#billingOrganisationId', element).val(id);
                                $('#billingTel1', element).val(data.tel);
                                $('#billingTel2', element).val(data.tel2);
                            }
                        });
                    }

                }
            });
        }
        else {
            $('a.deleteaddress').remove();
            $('a.addDispatch', element).hide();
            $('#addressform input, #addressform select').attr('readonly', 'readonly').addClass('readonly');
        }


        $('a.addresstab').click(openTab);



        var clearAddressError = function(element) {
            if (!options.readonly) {
                if ($(element).attr("value").length > 0) {
                    $('#addresses').find('.errorHolder').empty();
                }
            }
        };

        var addrFirstLine = $('#addressline1')

        addrFirstLine.change(clearAddressError(addrFirstLine));
        addrFirstLine.keyup(clearAddressError(addrFirstLine));

        var tablist = $('.tablist', element);
        var tablistbutton = $('a.tablistbutton', element).click(function() {
            tablist.toggle().scrollTo('a.selected');
            return false;
        });
        $('a', tablist).click(openTab);

        $(document).bind('click', function() {
            if (!$(this).hasClass('tablistbutton')) {
                tablist.hide();
            }
        });

        getAddresses({ openPart: 'last' });

        setTabsAndBilling();

        function openTab() {
            var tab = $(this);
            if (tab.data('orderPartId') > 0) {
                saveCurrentAddress({ action: 'GET', getPart: tab.data('orderPartId') });
            }
            tablist.hide();
            return false;
        }

        function setCurrentAddress(data) {
            if (!options.readonly) {
                personSelector.trigger('set', [data.personId, data.firstname, true]);
                organisationSelector.trigger('set', [data.organisationId, data.organisation, true]);
                $('input#division').val(data.division);
                $('input#addressline1').val(data.addressline1);
                $('input#addressline2').val(data.addressline2);
                $('input#addressline3').val(data.addressline3);
                $('input#addressline4').val(data.addressline4);
                $('input#towncity').val(data.towncity);
                $('input#county').val(data.county);
                $('input#postcode').val(data.postcode);
                $('select#countryId').val(data.countryId != null ? data.countryId : 'null');
                $('input#orderPartId').val(data.orderPartId);

                $('#tel1', element).val(data.tel1);
                $('#tel2', element).val(data.tel2);
                $('#mobile', element).val(data.mobile);

                billingPersonSelector.trigger('set', [data.billingPersonId, data.billingFirstname, true]);
                billingOrganisationSelector.trigger('set', [data.billingOrganisationId, data.billingOrganisation, true]);
                $('input#billingDivision').val(data.billingDivision);
                $('input#billingAddressline1').val(data.billingAddressline1);
                $('input#billingAddressline2').val(data.billingAddressline2);
                $('input#billingAddressline3').val(data.billingAddressline3);
                $('input#billingAddressline4').val(data.billingAddressline4);
                $('input#billingTowncity').val(data.billingTowncity);
                $('input#billingCounty').val(data.billingCounty);
                $('input#billingPostcode').val(data.billingPostcode);
                $('select#billingCountryId').val(data.billingCountryId != null ? data.billingCountryId : 'null');

                $('#billingTel1', element).val(data.billingTel1);
                $('#billingTel2', element).val(data.billingTel2);
                $('#billingMobile', element).val(data.billingMobile);

                $('#useDeliveryForBilling', element).attr('checked', data.useDeliveryForBilling).change();
            }
            else {
                function addLineIfNotBlank(add) {
                    var str = '';
                    if (add != '')
                        str += add + '<br />';
                    return str;
                }
                $('#addressform #deliveryAddress').html(
                    '<h3>Delivery Details</h3>' + 
                    addLineIfNotBlank(data.firstname) +
                    addLineIfNotBlank(data.organisation) +
                    addLineIfNotBlank(data.division) +
                    addLineIfNotBlank(data.addressline1) +
                    addLineIfNotBlank(data.addressline2) +
                    addLineIfNotBlank(data.addressline3) +
                    addLineIfNotBlank(data.addressline4) +
                    addLineIfNotBlank(data.towncity) +
                    addLineIfNotBlank(data.county) +
                    addLineIfNotBlank(data.postcode) +
                    addLineIfNotBlank(data.country) + '<br />' +
                    addLineIfNotBlank('<b>Telephone</b>: ' + data.tel1) +
                    addLineIfNotBlank('<b>Alt. Telephone</b>: ' + data.tel2) +
                    addLineIfNotBlank('<b>Mobile</b>: ' + data.mobile) + '<br />'
                );

                if (!data.useDeliveryForBilling) {
                    $('#addressform #billingAddress').html(
                        '<h3>Billing Details</h3>' + 
                        addLineIfNotBlank(data.billingFirstname) +
                        addLineIfNotBlank(data.billingOrganisation) +
                        addLineIfNotBlank(data.billingDivision) +
                        addLineIfNotBlank(data.billingAddressline1) +
                        addLineIfNotBlank(data.billingAddressline2) +
                        addLineIfNotBlank(data.billingAddressline3) +
                        addLineIfNotBlank(data.billingAddressline4) +
                        addLineIfNotBlank(data.billingTowncity) +
                        addLineIfNotBlank(data.billingCounty) +
                        addLineIfNotBlank(data.billingPostcode) +
                        addLineIfNotBlank(data.billingCountry) + '<br />' +
                        addLineIfNotBlank('<b>Telephone</b>: ' + data.billingTel1) +
                        addLineIfNotBlank('<b>Alt. Telephone</b>: ' + data.billingTel2) +
                        addLineIfNotBlank('<b>Mobile</b>: ' + data.billingMobile) + '<br />'
                    );
                }
            }

            $('input#orderPartId').val(data.orderPartId);

        }

        function leftTrunc(str, maxSize) {
            if (str.length > maxSize) {
                str = str.substr(0, maxSize - 3) + '...';
            }
            return str;
        }

        function getTabName(item) {
            var tabName = item.firstname != '' ? item.firstname : item.organisation;
            if (item.orderPartId == 0 || tabName == '') {
                tabName = 'New Address';
            }
            return tabName;
        }

        function drawTab(address) {
            var tabName = getTabName(address);

            var link = $('<a/>').attr('href', '#').attr('title', tabName).html(leftTrunc(tabName, 15)).addClass('addresstab').click(openTab);
            link.data('orderPartId', address.orderPartId);

            $('ul.addresstabs li.addDispatch').before($('<li></li>').append(link));
            return link;
        }

        function drawListItem(address) {
            var tabName = getTabName(address);
            var link = $('<a />').attr('href', '#').html(tabName).click(openTab);
            link.data('orderPartId', address.orderPartId);
            tablist.append($('<li></li>').append(link));
            return link;
        }

        function setUpTabs(currentAddress, addresses) {
            $('ul.addresstabs a.addresstab').parents('li').remove();
            tablist.empty();

            var MAX_TABS = 4;
            var numTabs = 0;

            if (currentAddress.orderPartId == 0) {
                drawTab(currentAddress).addClass('selected');
                drawListItem(currentAddress).addClass('selected');
                numTabs++;
            }

            $.each(addresses, function(index, item) {
                if ((addresses.length - index <= (MAX_TABS - numTabs) || parseInt(item.orderPartId) == parseInt(currentAddress.orderPartId) || numTabs > 0) && numTabs < MAX_TABS) {
                    var newTab = drawTab(item);
                    if (item.orderPartId == currentAddress.orderPartId)
                        newTab.addClass('selected');
                    numTabs++;
                }
                var newListItem = drawListItem(item);
                if (item.orderPartId == currentAddress.orderPartId)
                    newListItem.addClass('selected');
            });


        }

        function saveCurrentAddress(parameters) {
            if (!$('#addressform').hasClass('loading')) {
                $('#addressform').addClass('loading');
                var data = {
                    orderId: $('input#orderId').val(),
                    orderPartId: $('input#orderPartId').val(),
                    action: parameters.action,
                    getPart: parameters.getPart,
                    dontSave: parameters.dontSave || options.readonly
                };

                if (!parameters.dontSave && !options.readonly) {
                    data = $.extend({
                        personId: personSelector.data('id'),
                        organisationId: organisationSelector.data('id'),
                        personId_text: $('input#name').val(),
                        organisationId_text: $('input#organisation').val(),
                        division: $('input#division').val(),
                        addressline1: $('input#addressline1').val(),
                        addressline2: $('input#addressline2').val(),
                        addressline3: $('input#addressline3').val(),
                        addressline4: $('input#addressline4').val(),
                        towncity: $('input#towncity').val(),
                        county: $('input#county').val(),
                        postcode: $('input#postcode').val(),
                        countryId: $('select#countryId').val(),
                        tel1: $('input#tel1').val(),
                        tel2: $('input#tel2').val(),
                        mobile: $('input#mobile').val()
                    }, data);
                }

                $.ajax({
                    url: 'orderprocessing_json_orderpart.asp',
                    dataType: 'json',
                    data: data,
                    complete: function(data, textStatus) {
                        $('#addressform').removeClass('loading');
                    },
                    success: function(data, textStatus) {
                        $(options.orderlineFieldset).trigger('refresh');
                        setCurrentAddress(data.currentAddress);
                        setUpTabs(data.currentAddress, data.allAddresses);

                    },
                    error: function(data, textStatus) {
                        alert('There was a problem saving that address. Please try again.');
                    },
                    type: 'POST'
                });
            }
        }

        function getAddresses(parameters) {
            parameters = $.extend({
                dontSave: true,
                action: 'GET',
                getPart: parameters.openPart
            }, parameters);
            saveCurrentAddress(parameters);
        }
    };
})(jQuery);

(function($) {
    $.fn.svOrderDetailsFieldset = function(options) {
        options = $.extend({
            dispatchFieldset: '',
            paymentFieldset: '',
            orderlineFieldset: ''
        }, options);

        return new $.OrderDetailsFieldset(this, options);
    };

    $.OrderDetailsFieldset = function(element, options) {
        function orderTypeChanged() {
            var orderTypeId = parseInt($('.orderTypeContainer input:radio:checked').val());
            if (orderTypeId == 1) {
                $('#orderMethodId').val(1) //1 is value for Telephone
            }
            else {
                $('#orderMethodId').val(4); //4 is value for Email
            }
            $(options.dispatchFieldset).trigger('setOrderType', orderTypeId);
            $(options.paymentFieldset).trigger('setOrderType', orderTypeId);
            $(options.orderlineFieldset).trigger('refresh');
        };
        var orderType = $('.orderTypeContainer input:radio', element).change(orderTypeChanged);



        function setOrderTypeOptions(id) {
            if (parseInt(id) > 0) {
                $.ajax({
                    url: 'contracts_json_contract.asp',
                    data: { contractId: id },
                    success: function(data, textStatus) {
                        if (data.services.length > 0) {
                            $('.orderTypeContainer').hide();
                            $.each(data.services, function() {
                                $('#orderTypeContainer_' + this.id).show();
                            });
                        }
                        else {
                            $('.orderTypeContainer').show();
                        }
                        $('.orderTypeContainer:visible input:radio').eq(0).attr('checked', true);
                        orderTypeChanged();
                    },
                    dataType: 'json'
                });
                
            }

        }

        var contractAutocomplete = $('#rootContractId_text');
        contractAutocomplete.svContractAutocomplete({
            onSet: function() {
                projectAutocomplete.trigger('reset');
                setOrderTypeOptions(contractAutocomplete.data('id'));
            }
        });

        var projectAutocomplete = $('#projectAutocomplete');
        projectAutocomplete.svProjectAutocomplete({
            rootContractSelector: '#rootContractId_text',
            onSet: function() {
                setOrderTypeOptions(projectAutocomplete.data('id'));
            }
        });

        $('#rootContractId').change(function() {
            var contractId = $(this).val();
            $.ajax({
                url: 'contracts_json_contract.asp',
                data: { contractId: contractId },
                success: function(data, textStatus) {
                    $('#orderType_' + data.typeId).attr('checked', 'checked').change();
                    $(options.orderlineFieldset).trigger('refresh');
                },
                dataType: 'json'
            });
        });
    };
})(jQuery);

(function($) {
    var orderTypes = { MAILORDER: 1, DISTRIBUTION: 2 };
    $.fn.svOrderPaymentFieldset = function(options) {
        options = $.extend({
            orderType: orderTypes.DISTRIBUTION
        }, options);

        return new $.OrderPaymentFieldset(this, options);
    };

    $.OrderPaymentFieldset = function(element, options) {
        var $element = $(element);
        options = $.metadata ? $.extend({}, options, $element.metadata()) : options;

        if (options.orderType == orderTypes.DISTRIBUTION)
            $element.hide();

        $(element).bind('setOrderType', function(obj, typeId) {
            options.orderType = typeId;
            if (options.orderType == orderTypes.MAILORDER) {
                $element.show()
            }
            else {
                $element.hide();
            }
        });
    };
})(jQuery);

(function($) {
    $.fn.svOrderConfirmationFieldset = function(options) {
        options = $.extend({
            customValidation: {},
            beforeSubmit: {},
            contractId: 0,
            orderId: 0,
            orderLineTable: '',
            firstAddressLine: '',
            urlHasLines: 'orderprocessing_json_hasOrderLines.asp',
            urlHasAddress: 'orderprocessing_json_hasDispatchAddress.asp',
			urlHasMultipleAddress: 'orderprocessing_json_hasDispatchAddress.asp',//1995
            cssClassInvalidProduct: 'productNotInContract',
            detailsSection: ''
        }, options);

        return new $.OrderConfirmationFieldset(this, options);
    };

    $.OrderConfirmationFieldset = function(element, options) {
        var OrderHasLines = function() {
            var hasLines = false;
            $.ajax({
                url: options.urlHasLines + '?orderid=' + options.orderId,
                error: function(data, textstatus) { },
                success: function(data, textStatus) {
                    if (data.readyToProcess) {
                        hasLines = true;
                    }
                },
                dataType: 'json',
                async: false
            });
            return hasLines;
        };

        var OrderHasAddress = function() {
            var hasAddress = false;
            if ($(options.firstAddressLine).attr('value').length > 0) {
                hasAddress = true;
                return hasAddress;
            }
            $.ajax({
                url: options.urlHasAddress + '?orderid=' + options.orderId,
                error: function(data, textstatus) { },
                success: function(data, textStatus) {
                    if (data.readyToProcess == true) {
                        hasAddress = true;
                    }
                },
                dataType: 'json',
                async: false
            });
            return hasAddress;
        };
		
		
		/*Bug 1995*/
        var OrderHasMultipleAddress = function() {
		            var hasDispatchAddressForDistribution = false;
 
                if ($(options.firstAddressLine).attr('value').length > 0) {
                    hasDispatchAddressForDistribution = true;
                    return hasDispatchAddressForDistribution;
                }
          

            $.ajax({
                url: options.urlHasMultipleAddress + '?orderid=' + options.orderId,
                error: function(data, textstatus) { },
                success: function(data, textStatus) {
                    if (data.readyToProcess == true) {
                        hasDispatchAddressForDistribution = true;
                    }
                },
                dataType: 'json',
                async: false
            });
            return hasDispatchAddressForDistribution;
        };
        /*Bug 1995*/
		

        var warningProductsModal = $('#warningProductsModal').svWarningProductsModal({
            ignore: function() {
                $('label.warningProduct', options.orderLineTable).remove();
                processOrder();
            },
            removeProject: function() {
                var contractIdField = $('input[name=contractId]', options.detailsSection);
                $.ajax({
                    url: 'contracts_json_getRootContract.asp',
                    data: { contractId: contractIdField.val() },
                    dataType: 'json',
                    type: 'post',
                    success: function(data, textStatus) {
                        contractIdField.val(data.id);
                        $('label.warningProduct', options.orderLineTable).remove();
                        processOrder();
                    }
                });
            },
            cancel: function() { }
        });
        var OrderHasWarningProducts = function() {
            var hasWarningProducts = ($(options.orderLineTable + ' label.warningProduct').length > 0);
            if (hasWarningProducts) {
                warningProductsModal.dialog('open');
            }
            return hasWarningProducts;
        };

        var invalidProductsModal = $('#invalidProductsModal').svInvalidProductsModal({});
        var OrderHasInvalidProducts = function() {
            var hasInvalidProducts = ($(options.orderLineTable + ' label.invalidProduct').length > 0);
            if (hasInvalidProducts) {
                invalidProductsModal.dialog('open');
            }
            return hasInvalidProducts;
        }

        $.validator.addMethod("hasOrderLines", OrderHasLines, "Order is not ready to process - Must have at least one order line.");
        $.validator.addMethod("hasDispatchAddress", OrderHasAddress, "Order is not ready to process - Must have at least one dispatch address.");
		 $.validator.addMethod("hasDispatchAddress", OrderHasMultipleAddress, "Order is not ready to process - At Atleast one of the addresses is incomplete");
 /*Bug 1995*/
       
        /*Bug hasDispatchAddressForDistribution
		K=R*/
        var formdom = $('form.createorder').get(0);
        var setupForm = function() {
            options.customValidation = $.extend({
                errorPlacement: function(error, element) {
                    error.appendTo(element.parent().find(".errorHolder"));
                },
                rules: {
                    errOrderLines: {
                        hasOrderLines: true
                    },
                    errDispatchAddress: {
                        hasDispatchAddress: true
                    },
                    /*Bug 1995*/
                    errDispatchAddresses: {
                        hasDispatchAddressForDistribution: true
                    }
                    /*Bug 1995*/
                }
            }, options.customValidation);
            $(formdom).validate(options.customValidation);
        };
        setupForm();

        $('input.save').click(function() {
            formdom.process.value = 'false';
            formdom.submit();
        });

        function processOrder() {
            if (($(formdom).valid() && !OrderHasInvalidProducts() && !OrderHasWarningProducts())) {
                formdom.process.value = 'true';
                formdom.submit();
            }
        }

        $('input.process').click(processOrder).keyup(function(e) {
            var code = (e.keyCode ? e.keyCode : e.which);
            if (code == 13) {
                processOrder();
            }
        });
    };
})(jQuery);

(function($) {
    $.fn.svRegistrationOptionsEditor = function(options) {
        options = $.extend({
    }, options);

    return new $.RegistrationOptionsEditor(this, options);
};

$.RegistrationOptionsEditor = function(element, options) {
    var newId = 0;

    var name = $('input[name=name_new]', element);
    var price = $('input[name=price_new]', element);
    var vatable = $('input[name=vatable_new]', element);

    var deleteRow = function() {
        tr = $(this).parents('tr');
        if (tr.data('new') == 'true')
            tr.remove();
        else {
            var priceInput = $('input[name^=price]', tr);
            var price = priceInput.val();
            tr.data('price', price).hide();
            priceInput.val('-100');
        }
        return false;
    };

    var appendRow = function(name, price, vatable) {
        var row = createRow(name, price, vatable);
        row.data('new', 'true');
        $('tr.addrow', element).before(row);
    };

    var createRow = function(name, price, vatable) {
        var id = newId++;
        var nameColumn = createNameColumn(id, name);
        var priceColumn = createPriceColumn(id, price);
        var vatableColumn = createVatableColumn(id, vatable);
        var removeColumn = createRemoveColumn(id);

        var row = $('<tr></tr>').append(nameColumn).append(priceColumn).append(vatableColumn).append(removeColumn);
        row.addClass('optionrow');
        return row;
    };

    var createNameColumn = function(id, name) {
        return $('<td><input name=\"name_new' + id + '\" value=\"' + name + '\" /></td>');
    };

    var createPriceColumn = function(id, price) {
        return $('<td>&pound;<input name=\"price_new' + id + '\" value=\"' + price + '\" class=\"price\" /></td>');
    };

    var createVatableColumn = function(id, vatable) {
        var input = '<input type=\"checkbox\" name=\"vatable_new' + id + '\"';
        if (vatable)
            input += ' checked=\"checked\"';
        input += ' />';
        return $('<td>' + input + '</td>'); ;
    };

    var createRemoveColumn = function(id) {
        var link = $('<a href=\"#\" class=\"remove imagebutton linkbutton\">remove</a>');
        link.click(deleteRow);
        return $('<td></td>').append(link);
    };
    

    var resetEditor = function() {
        $('tr.optionrow').each(function() {
            var tr = $(this);
            
            if (tr.data('price') > 0) {
                $('input[name^=price]', tr).val(tr.data('price'));
                tr.removeData('price');
                tr.show();
            }
            else if (tr.data('new') == 'true')
                tr.remove();
        });
    };

    $('.addoption', element).click(function() {
        if (name.val() != '' && !isNaN(price.val())) {
            appendRow(name.val(), price.val(), vatable.attr('checked'));
            name.val('');
            price.val('');
            vatable.attr('checked', true);
        }
        return false;
    });

    $('a.remove', element).click(deleteRow);

    element.bind('reset', function() {
        resetEditor();
    });
};
})(jQuery);

(function($) {
    $.fn.svWidgetControl = function(options) {
        var opts = $.extend({}, $.fn.svWidgetControl.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            var mode = 'view';

            $('a.edit, a.cancel', $element).click(function() {
                toggleEditor();
                return false;
            });

            $('a.save', $element).click(function() {
                $(this).html('saving...');
                var data = $.extend({}, $.parseQuery($('form', $element).serialize()), { widgetId: opts.widgetId, key: opts.key });
                $.ajax({
                    url: opts.url,
                    data: $.extend({}, data, opts.getSubmitData()),
                    type: 'post',
                    dataType: 'html',
                    success: function(data, textStatus) {
                        $element.replaceWith($(data).svWidgetControlFactory());
                    },
                    error: function() { },
                    complete: function() { $('a.save', $element).html('save') }
                })
                return false;
            });

            $('a.delete_widget', $element).click(function() {
                if (confirm('Are you sure you want to delete this block?')) {
                    var deleteOptions = $(this).metadata();
                    $.ajax({
                        url: deleteOptions.url,
                        data: { widgetId: deleteOptions.id, action: deleteOptions.action, key: deleteOptions.key },
                        success: function() {
                            $element.remove();
                        },
                        type: 'post'
                    });
                }
                return false;
            });

            $('input.pageLookup', $element).svPageLookup();

            function toggleEditor() {
                $('div.display', $element).toggle();
                $('div.editor', $element).toggle();
                $('a.edit, a.cancel, a.save', $element).toggle();
                if (mode == 'view') {
                    opts.onEdit();
                    mode = 'edit';
                }
                else {
                    opts.onView();
                    mode = 'view';
                }
            };
        });
    };

    $.fn.svWidgetControl.defaults = {
        onEdit: function() { },
        onView: function() { },
        getSubmitData: function() { return {}; }
    };
})(jQuery);

(function($) {
    $.fn.svContentWidgetControl = function(options) {

        var opts = $.extend({}, $.fn.svContentWidgetControl.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            var htmlBodySet = false;

            opts.onEdit = function() {
                if (!htmlBodySet) {
                    $('textarea.richtext', $element).tinymce({
                        script_url: '/tinymce/jscripts/tiny_mce/tiny_mce.js',
                        theme_advanced_toolbar_location: "top",
                        theme: "advanced",
                        width: "530",
                        skin: "o2k7",
                        height: "250",
                        theme_advanced_toolbar_align: "left",
                        plugins: "fullscreen",
                        content_css: "/style/paintbox/combined.css",
                        theme_advanced_buttons1: "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,formatselect,fontselect,fontsizeselect",
                        theme_advanced_buttons2: "cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,insertdate,inserttime,preview,|,forecolor,backcolor",
                        theme_advanced_buttons3: "hr,removeformat,visualaid,|,sub,sup,|,charmap,|,fullscreen"
                    });
                    htmlBodySet = true;
                }
            }

            opts.getSubmitData = function() {
                var content = $('textarea', $element).tinymce().getContent();
                return { content: content };
            }

            $element.svWidgetControl(opts);
        });
    };

    $.fn.svContentWidgetControl.defaults = {
        url: '',
        key: ''
    };
})(jQuery);
(function($) {
    $.fn.svRegistrationWidgetControl = function(options) {
        var opts = $.extend({}, $.fn.svRegistrationWidgetControl.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            var htmlBodySet = false;

            opts.onEdit = function() {
                if (!htmlBodySet) {
                    $('textarea.richtext', $element).tinymce({
                        script_url: '/tinymce/jscripts/tiny_mce/tiny_mce.js',
                        theme_advanced_toolbar_location: "top",
                        theme: "advanced",
                        width: "530",
                        skin: "o2k7",
                        height: "250",
                        theme_advanced_toolbar_align: "left",
                        plugins: "fullscreen",
                        content_css: "/style/paintbox/combined.css",
                        theme_advanced_buttons1: "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,formatselect,fontselect,fontsizeselect",
                        theme_advanced_buttons2: "cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,insertdate,inserttime,preview,|,forecolor,backcolor",
                        theme_advanced_buttons3: "hr,removeformat,visualaid,|,sub,sup,|,charmap,|,fullscreen"
                    });
                    htmlBodySet = true;
                }
            };

            opts.getSubmitData = function() {
                var intro = $('textarea.richtext', $element).tinymce().getContent();
                return {
                    intro: intro
                };
            };

            $element.svWidgetControl(opts);
        });
    };

    $.fn.svRegistrationWidgetControl.defaults = {};
})(jQuery);
(function($) {
    $.fn.svWidgetControlFactory = function(options) {
        return this.each(function() {
            var $element = $(this);
            if ($element.hasClass('content_block'))
                $element.svContentWidgetControl();
            else if ($element.hasClass('event_registration'))
                $element.svRegistrationWidgetControl();
            else if ($element.hasClass('document_list'))
                $element.svDocumentListWidgetControl()
            else if ($element.hasClass('document_display'))
                $element.svDocumentDisplayWidgetControl();
            else if ($element.hasClass('login'))
                $element.svLoginWidgetControl();
            else if ($element.hasClass('response_form')) {
                $element.svResponseFormWidgetControl();
            }
            else
                $element.svWidgetControl();
        });
    };
})(jQuery);
(function($) {
    $.fn.svOrderPicker = function(options) {

        var opts = $.extend({}, $.fn.svOrderPicker.defaults, options);

        return this.each(function() {
            var $element = $(this);

            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            $(':checkbox', $element).change(function() {
                var li = $(this).parents('li').eq(0);
                $(':checkbox', li).attr('checked', $(this).attr('checked'));
                checkChildStatus($(':checkbox:first', $element));
            });

            $('a.showhide', $element).click(function() {
                var $a = $(this);
                $('+ ul:first', $a).slideToggle();
                if ($a.html() == opts.showdetails)
                    $a.html(opts.hidedetails);
                else
                    $a.html(opts.showdetails);
                return false;
            });

            var i = 0;
            function checkChildStatus($ul) {
                var childrenChecked = true;
                var children = $('+ div + a + ul:first > li > :checkbox, + a + ul:first > li > :checkbox', $ul);
                if (children.length > 0) {
                    children.each(function() {
                        var result = checkChildStatus($(this));
                        childrenChecked = childrenChecked && result;
                        return true;
                    });

                    if (childrenChecked)
                        $ul.attr('checked', 'checked');
                    else
                        $ul.attr('checked', '');
                }
                return childrenChecked && $ul.attr('checked');
            }

            $element.bind('checkall', function() {
                $(':checkbox', $element).attr('checked', 'checked');
            });

            $element.bind('uncheckall', function() {
                $(':checkbox', $element).attr('checked', '');
            });
        });
    };

    $.fn.svOrderPicker.defaults = {
        url: '',
        key: '',
        showdetails: 'show details',
        hidedetails: 'hide details'
    };
})(jQuery);
(function($) {
    $.fn.svOrderPacker = function(options) {

        var opts = $.extend({}, $.fn.svOrderPacker.defaults, options);

        return this.each(function() {
            var $element = $(this);

            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            $element.bind('checkall', function() {
                $(':checkbox', $element).attr('checked', 'checked');
            });

            $element.bind('uncheckall', function() {
                $(':checkbox', $element).attr('checked', '');
            });
        });
    };

    $.fn.svOrderPacker.defaults = {};
})(jQuery);
(function($) {  
      $.fn.svStripHTMLTags = function() {  
         var regexp = /<("[^"]*"|'[^']*'|[^'">])*>/gi;  
         this.each(function() {
            var text = $(this).text();
             text = text.replace(regexp, '');
             text = text.replace('&nbsp;', ' ');
             $(this).text(text);  
         });  
         return $(this);  
     }  
})(jQuery);  
(function($) {
    $.fn.svDocumentListWidgetControl = function(options) {
        var opts = $.extend({}, $.fn.svDocumentListWidgetControl.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            $('input[name=listTypeId]', $element).change(function() {
                updateRoleSelector()
            });

            function updateRoleSelector() {
                var typeId = $('input[name=listTypeId]:checked', $element).val()
                if (typeId != '3') {
                    $('.rolelist input').attr('disabled', 'disabled');
                    $('.rolelist label').addClass('disabled');
                }
                else {
                    $('.rolelist input').attr('disabled', '');
                    $('.rolelist label').removeClass('disabled');
                }
            }


            updateRoleSelector();

            $element.svWidgetControl(opts);
        });
    };

    $.fn.svDocumentListWidgetControl.defaults = {};
})(jQuery);
(function($) {
    $.fn.svDocumentDisplayWidgetControl = function(options) {
        var opts = $.extend({}, $.fn.svDocumentDisplayWidgetControl.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            $('input[name=displayTypeId]', $element).change(function() {
                updateDocumentSelector()
            });

            function updateDocumentSelector() {
                var typeId = $('input[name=displayTypeId]:checked', $element).val()
                if (typeId == '1') {
                    $('input[name=documentId]', $element).attr('disabled', 'disabled');
                    $('label[for=documentId]', $element).addClass('disabled');
                }
                else {
                    $('input[name=documentId]', $element).attr('disabled', '');
                    $('label[for=documentId]', $element).removeClass('disabled');
                }
            }


            updateDocumentSelector();

            $element.svWidgetControl(opts);
        });
    };

    $.fn.svDocumentDisplayWidgetControl.defaults = {};
})(jQuery);
(function($) {
    $.fn.svLoginWidgetControl = function(options) {
        var opts = $.extend({}, $.fn.svLoginWidgetControl.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            var updatePasswordSelector = function() {
                if (passwordCheck.is(':checked')) {
                    passwordPageSelector.attr('disabled', '');
                }
                else {
                    passwordPageSelector.attr('disabled', 'disabled');
                }
            };
            
            var passwordCheck = $('input[name=usePasswordLink]', $element).click(updatePasswordSelector);
            var passwordPageSelector = $('input[name=passwordLink]', $element);

            var updateRegisterSelector = function() {
                if (registerCheck.is(':checked')) {
                    registerPageSelector.attr('disabled', '');
                }
                else {
                    registerPageSelector.attr('disabled', 'disabled');
                }
            };
            var registerCheck = $('input[name=useRegisterLink]', $element).click(updateRegisterSelector);
            var registerPageSelector = $('input[name=registerLink]', $element);

            updatePasswordSelector();
            updateRegisterSelector();

            $element.svWidgetControl(opts);
        });
    };

    $.fn.svLoginWidgetControl.defaults = {};

})(jQuery);
(function($) {
    $.fn.svToDoModal = function(options) {
        var opts = $.extend({}, $.fn.svToDoModal.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            var personAutocomplete = $('input.personautocomplete', $element).svPersonAutocomplete({ fieldName: 'entityId' });

            $element.dialog({
                autoOpen: false,
                width: 750,
                height: 250,
                modal: true
            });

            function resetForm() {
                $('form', $element).each(function() { this.reset() });
            }

            function closeDialog() {
                $element.dialog('close');
                resetForm();
            }

            function loadToDo(id, key) {
                var form = $('form', $element).get(0);
                $.ajax({
                    data: { todoId: id },
                    dataType: 'json',
                    type: 'POST',
                    url: form.action,
                    success: function(data, textStatus) {
                        personAutocomplete.trigger('set', [data.entityId, data.entityName, true]);
                        form.entityTypeId.value = data.entityTypeId;
                        form.name.value = data.name;
                        form.duedate.value = data.dueDate;
                        form.typeId.value = data.typeId;
                        form.key.value = data.editKey;
                        form.todoId.value = data.id;
                        form.statusId.checked = data.complete;
                        form.frmAction.value = 'EDIT';

                        $element.dialog('open');
                    }
                });
            }

            $element.bind('open', function(event, options) {
                resetForm();
                var form = $('form', $element).get(0);
                if (isNaN(options.id)) {
                    personAutocomplete.trigger('set', [options.entityId, options.entityName, true]);
                    form.entityTypeId.value = options.entityTypeId;
                    $element.dialog('open');
                }
                else {
                    loadToDo(options.id, options.key);
                }
            });

            $('a.cancel', $element).click(function() {
                closeDialog();

                return false;
            });

            $('input.freedate').svDatePicker();


            $('a.save', $element).click(function() {
                var form = $('form', $element).get(0);
                $(form).validate();
                if ($(form).valid()) {
                    url = form.action;
                    $.ajax({
                        data: $(form).serialize(),
                        url: url,
                        type: 'POST',
                        success: function() {
                            opts.onSuccess(form.entityTypeId.value, form.entityId.value);
                            closeDialog();
                        }
                    });
                }
                return false;
            });
        });
    };

    $.fn.svToDoModal.defaults = {
        onSuccess: function(entityTypeId, entityId) { }
    };
})(jQuery);

(function($) {
    $.fn.svActivityNoteEditor = function(options) {
        var opts = $.extend({}, $.fn.svActivityNoteEditor.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            var editor = $element.svEditableSection({
                onSuccess: function() {
                    initNotes();
                }
            });

            var initNotes = function() {
                var newnote = $('#newnote').svActivityNote({
                    newNote: true,
                    onCancel: function() {
                        $('#newnote').hide();
                    },
                    onSuccess: function() {
                    editor.refresh();
                    }
                });

                $('.editableactivitynote').each(function() {
                    $(this).svActivityNote({
                        onSuccess: function() {
                        editor.refresh();
                        }
                    })
                });

                $('a.addnote').click(function() {
                    $('#newnote').toggle();
                    newnote.openEditor()
                    return false;
                });
            };

            initNotes();
        });
    };

    $.fn.svActivityNoteEditor.defaults = {
        onSuccess: function(entityTypeId, entityId) { }
    };
})(jQuery);

(function($) {
    $.fn.svPageLookup = function(options) {
        var opts = $.extend({}, $.fn.svPageLookup.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            function showPageLookup() {
                $('<div />').svPageLookupModal({ onSelect: function(url) { $element.val(url); } });
                return false;
            }

            $element.after($('<input type=\"button\" value=\"Lookup\" />').click(showPageLookup));
        });
    };

    $.fn.svPageLookup.defaults = {};
})(jQuery);

(function($) {
    $.fn.svPageLookupModal = function(options) {
        options = $.extend({
            query: '',
            onSelect: function(url) { }
        }, options);
        return new $.PageLookupModal(this, options);
    };

    $.PageLookupModal = function(element, options) {
        var $element = $(element);
        var $viewport = $('<div></div>');

        $element.append($viewport);
        $element.dialog({ autoOpen: true, width: 300, height: 450, title: 'Select Page', modal: true });

        function loadPage(url) {
            $viewport.load(url, setupPage);

            function setupPage() {
                $('a', $element).click(function() {
                    var $this = $(this);
                    if (!$this.hasClass('page')) {
                        var href = $this.attr('href');
                        if (href != '' && href != '#') {
                            loadPage($this.attr('href'));
                            return false;
                        }
                        else {
                            return true;
                        }
                    }
                    else {
                        var data = $this.metadata()
                        options.onSelect('page.asp?id=' + data.id);
                        $element.dialog('close');
                        return false;
                    }
                });

                $element.css({ padding: '0px' });
                $viewport.css({ height: 417, overflow: 'auto', padding: '5px' });
            }
        }

        loadPage('websites_lookupPage.asp?' + location.search.substring(1));
    };
})(jQuery);
$(function() {
    (function($) {
        $.fn.svMailingHeaderEditableSection = function(options) {
            var opts = $.extend({}, $.fn.svMailingHeaderEditableSection.defaults, options);

            return this.each(function() {
                var $element = $(this);
                opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

                var HTMLbody;
                var HTMLbodyset = false

                $element.svEditableSection({
                    action: opts.action,
                    submitStyle: opts.submitStyle,
                    onEditable: function() {
                        if (!HTMLbodyset) {
                            $('textarea.richtext').tinymce({
                                script_url: '/tinymce/jscripts/tiny_mce/tiny_mce.js',
                                theme_advanced_toolbar_location: "top",
                                theme: "advanced",
                                width: "530",
                                skin: "o2k7",
                                height: "200",
                                theme_advanced_toolbar_align: "left",
                                plugins: "fullscreen",
                                content_css: "style/paintbox/combined.css",
                                theme_advanced_buttons1: "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,formatselect,fontselect,fontsizeselect",
                                theme_advanced_buttons2: "cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,insertdate,inserttime,preview,|,forecolor,backcolor",
                                theme_advanced_buttons3: "hr,removeformat,visualaid,|,sub,sup,|,charmap,|,fullscreen",
                                extended_valid_elements: "body[alink|background|bgcolor|class|dir<ltr?rtl|id|lang|link|"
                                                        + "style|title|text|vlink],"
                                                        + "head[dir<ltr?rtl|lang|profile],"
                                                        + "title[dir<ltr?rtl|lang],"
                                                        + "link[charset|class|dir<ltr?rtl|href|hreflang|id|lang|media|onclick"
                                                        + "|ondblclick|onkeydown|onkeypress|onkeyup|onmousedown|onmousemove"
                                                        + "|onmouseout|onmouseover|onmouseup|rel|rev|style|title|target|type],"
                                                        + "meta[content|dir<ltr?rtl|http-equiv|lang|name|scheme],"
                                                        + "style[dir<ltr?rtl|lang|media|title|type],"
                                                        + "html[dir<ltr?rtl|lang|version]"
                            });
                            HTMLbodyset = true;
                        };
                    },
                    beforeSubmit: function() {
						var content = $('textarea.richtext').tinymce().getContent();
                        $('#HTMLbody').val(content);
                        return true;
                    },
                    onSuccess: function() {
                        setup();
                    },
                    customValidation: {
                        messages: {
                            fromAddress: {
                                required: "Please enter an email address for the mailing to be sent from.",
                                email: "Sorry, that email address is not valid."
                            },
                            title: {
                                required: "Please enter a title for this mailing."
                            }
                        }
                    }
                });

                var setup = function() {
                    HTMLbodyset = false;

                    var btnCopyFromHTML = $('#copyFromHTMLBody').click(function() {
                        var editorId = $('textarea.richtext').attr('id');
                        var content = tinyMCE.get(editorId).getContent();
                        $('#copiedtext').hide();
                        $('#copiedtext').text(content);
                        $('#copiedtext').svStripHTMLTags();
                        $('#plaintextbody').val(unescape($('#copiedtext').text()));
                        return false;
                    });
                };

                setup();
            });
        };

        $.fn.svMailingHeaderEditableSection.defaults = {
            action: 'EDIT',
            submitStyle: 'async'
        };
    })(jQuery);
});
(function($) {
		  
    $.fn.svDatePicker = function(options) {
        var opts = $.extend({}, $.fn.svDatePicker.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            $element.after($('<a href=\"#\" class=\"iconlink calendar_iconlink\">date picker</a>').click(function() {
                var date = Date();
                var time = Date();
                $.ajax({
                    url: opts.url,
                    data: { datetime: typeof opts.datetime == 'function' ? opts.datetime($element) : opts.datetime },
                    success: function(data, textStatus) {
                        date = $.datepicker.parseDate('yy-mm-dd', data.datetime);
                        time = data.datetime.substring(data.datetime.length - 8);
                        openModal(date, time, opts);
                    },
                    dataType: 'json',
                    complete: function(request, textStatus) {

                    },
                    error: function() {
                        openModal(datetime, opts);
                    }

                });
                return false;
            }));

            function forceLeadingZero(number) {
                return number < 10 ? '0' + number : number;
            }

            var window;
            var hourSelect;
            var minSelect;
            var datepicker;

            function openModal(date, time, opts) {
                if (!window) {
                    window = $('<div class=\"svDatePicker\"><div class=\"datepicker\" /><div class=\"timepicker\" /></div>').dialog({
                        autoopen: false,
                        title: 'Select Date',
                        width: 420,
                        height: 240
                    });

                    datepicker = $('.datepicker', window).datepicker({
                        dateFormat: 'dd/mm/yy'
                    });

                    hourSelect = $('<select name=\"hour\" />');
                    for (i = 0; i < 24; i++) {
                        hourSelect.append('<option value=\"' + forceLeadingZero(i) + '\">' + forceLeadingZero(i) + '</option>');
                    }


                    minSelect = $('<select name="\minute\" />');
                    for (i = 0; i < 60; i += 1) {
                        minSelect.append('<option value=\"' + forceLeadingZero(i) + '\">' + forceLeadingZero(i) + '</option>');
                    }

                    var actionRow = $('<div class=\"actionrow\" />');
                    actionRow.append($('<a href=\"#\" class=\"linkbutton save\">ok</a>').click(function() {
                        var date = datepicker.datepicker('getDate');
                        $element.val($.datepicker.formatDate('dd/mm/yy', date) + ' ' + hourSelect.val() + ':' + minSelect.val());
                        window.dialog('close');
						typeof opts.afterClose == 'function' ? opts.afterClose() : opts.afterClose;
                        return false;
                    }));
                    actionRow.append(' ');
                    actionRow.append($('<a href=\"#\">cancel</a>').click(function() {
                        window.dialog('close');
						typeof opts.afterClose == 'function' ? opts.afterClose() : opts.afterClose;
                        return false;
                    }));

                    $('.timepicker', window).append('Time: ');
                    $('.timepicker', window).append(hourSelect);
                    $('.timepicker', window).append(':');
                    $('.timepicker', window).append(minSelect);

                    window.append(actionRow);
                }

                hourSelect.val(time.substring(0, 2));
                minSelect.val(time.substring(3, 5));
                datepicker.datepicker('setDate', date);

                window.dialog('open');
            }
        });
    };

    $.fn.svDatePicker.defaults = {
        datetime: function($element) { return $element.val(); },
        url: 'diary_convertstringtodate.asp',
		afterClose: ''
    };
})(jQuery);

(function($) {
    $.fn.svLinkPopUp = function(options) {
        var opts = $.extend({}, $.fn.svLinkPopUp.defaults, options);

        return this.each(function() {

            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            // options
            var distance = 10;
            var time = 250;
            var hideDelay = 170;
            var showDelay = 1000;

            var hideDelayTimer = null;
            var showDelayTimer = null;
            // tracker
            var beingShown = false;
            var shown = false;

            var gotData = false;


            var popup = $('<div class=\"linkPopUp\" />').css('opacity', 0);



            $(document.body).append(popup);
            // set the mouseover and mouseout on both element
            $([$element.get(0), popup.get(0)]).mouseover(function() {
                // stops the hide event if we move from the trigger to the popup element
                if (hideDelayTimer)
                    clearTimeout(hideDelayTimer);
                // don't trigger the animation again if we're being shown, or already visible
                if (beingShown || shown) {
                    return;
                } else {
                    beingShown = true;
                    showDelayTimer = setTimeout(function() {
                        showDelayTimer = null;
                        if (!gotData) {
                            $.ajax({
                                url: opts.url,
                                data: typeof opts.data == 'function' ? opts.data($element) : opts.data,
                                dataType: 'html',
                                success: function(data, textStatus) {
                                    popup.html(data);
                                    gotData = true;
                                    showPopup();
                                }
                            });
                        }
                        else {
                            showPopup();
                        }

                    }, showDelay);
                }
            }).mouseout(function() {
                // reset the timer if we get fired again - avoids double animations
                if (hideDelayTimer) clearTimeout(hideDelayTimer);
                if (beingShown) {
                    clearTimeout(showDelayTimer);
                    beingShown = false;
                }

                // store the timer so that it can be cleared in the mouseover if required
                hideDelayTimer = setTimeout(function() {
                    hideDelayTimer = null;
                    popup.animate({
                        top: '-=' + distance + 'px',
                        opacity: 0
                    }, time, 'swing', function() {
                        // once the animate is complete, set the tracker variables
                        shown = false;
                        // hide the popup entirely after the effect (opacity alone doesn't do the job)
                        popup.css('display', 'none');
                    });
                }, hideDelay);
            });

            function showPopup() {
                var windowWidth = $(window).width();
                var initTop = $element.offset().top - (popup.height() + distance);
                var initLeft = $element.offset().left;
                popup.css({
                    top: initTop,
                    left: initLeft + popup.width() > windowWidth ? (windowWidth - popup.width()) - 15 : initLeft,
                    display: 'block' // brings the popup back in to view
                }).animate({
                    top: '-=' + distance + 'px',
                    opacity: 1
                }, time, 'swing', function() {
                    // once the animation is complete, set the tracker variables
                    beingShown = false;
                    shown = true;
                });
            }
        });
    };

    $.fn.svLinkPopUp.defaults = {
        url: '',
        data: function($element) { return { id: $element.metadata().id} }
    };
})(jQuery);
(function($) {
    $.fn.svProductLinkPopUp = function(options) {
        var opts = $.extend({}, $.fn.svProductLinkPopUp.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            $element.svLinkPopUp(opts);
        });
    };

    $.fn.svProductLinkPopUp.defaults = {
        url: 'productcatalogue_productpopup.asp',
        data: function($element) { return { prodId: $element.metadata().id} }
    };
})(jQuery);

$(function() {
    $('a.product').livequery(function() {
        $(this).svProductLinkPopUp();
    });
});

(function($) {
    $.fn.svPersonLinkPopUp = function(options) {
        var opts = $.extend({}, $.fn.svPersonLinkPopUp.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            $element.svLinkPopUp(opts);
        });
    };

    $.fn.svPersonLinkPopUp.defaults = {
        url: 'contactmanager_personpopup.asp',
        data: function($element) { return { contId: $element.metadata().id} }
    };
})(jQuery);

$(function() {
    $('#mainsection_container a.person').livequery(function() {
        $(this).svPersonLinkPopUp();
    });
});

(function($) {
    $.fn.svOrderSpecialInstrucitonsFieldset = function(options) {
        options = $.extend({
    }, options);

    return new $.OrderSpecialInstrucitonsFieldset(this, options);
};

$.OrderSpecialInstrucitonsFieldset = function(element, options) {
    var $element = $(element);
    options = $.metadata ? $.extend({}, options, $element.metadata()) : options;

    var $fields = $('input, select, textarea', $element[0]);
    var $addbutton = $('a.addnote', $element[0]).click(function() {
        $.ajax({
            dataType: 'html',
            url: options.url,
            data: serializeData(options.orderId, $fields, 'ADD'),
            success: function(data, textStatus) {
                $fields.val('');
                $('div.instructions', $element[0]).html(data);
            },
            type: 'POST'
        });
        return false;
    });

    $('a.deletenote', $element[0]).livequery(function() {
        $(this).click(function() {
            if (confirm('Are you sure you want to delete this special instruction?')) {
                var linkData = $(this).metadata();
                $.ajax({
                    dataType: 'html',
                    url: options.url,
                    data: { instructionId: linkData.id, action: 'DELETE', key: linkData.key, orderId: linkData.orderId },
                    success: function(data, textStatus) {
                        $('div.instructions', $element[0]).html(data);
                    },
                    type: 'POST'
                });
            }
            return false;
        });
    });
};

function serializeData(orderId, $fields, action) {
    var dataString = 'orderId=' + orderId;
    $fields.each(function() {
        var $this = $(this);
        dataString += '&' + $this.attr('name') + '=' + escape($this.val());
    });
    dataString += '&action=' + action;
    return dataString;
};
})(jQuery);

(function($) {
    $.fn.svColourPicker = function(options) {
        var opts = $.extend({}, $.fn.svColourPicker.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            $element.css('backgroundColor', $element.val().indexOf('#') == 0 ? $element.val() : '#' + $element.val());

            $element.ColorPicker({
                onChange: function(hsb, hex, rgb) {
                    $element.val('#' + hex);
                    $element.css('backgroundColor', '#' + hex);
                }
            });
        });
    };

    $.fn.svColourPicker.defaults = {
        onSuccess: function(entityTypeId, entityId) { }
    };
})(jQuery);

(function($) {
    $.fn.svColourModal = function(options) {
        var opts = $.extend({}, $.fn.svColourModal.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            $element.dialog({
                autoOpen: false,
                width: 750,
                height: 250,
                modal: true
            });
            $('input.colourpicker', $element[0]).svColourPicker();
            
            function resetForm() {
                $('form', $element).each(function() { this.reset() });
            }

            function closeDialog() {
                $element.dialog('close');
                resetForm();
            }

            $element.bind('open', function(event, options) {
                resetForm();
            });

            $('a.cancel', $element).click(function() {
                closeDialog();

                return false;
            });

            $('a.save', $element).click(function() {
                var form = $('form', $element).get(0);
                $(form).validate();
                if ($(form).valid()) {
                    url = form.action;
                    $.ajax({
                        data: $(form).serialize(),
                        url: url,
                        type: 'POST',
                        success: function(data, textStatus) {
                            opts.onSuccess(data);
                            closeDialog();
                        },
                        dataType:'html'
                    });
                }
                return false;
            });
        });
    };

    $.fn.svColourModal.defaults = {
        onSuccess: function(entityTypeId, entityId) { }
    };
})(jQuery);

(function($) {
    $.fn.svProductCategoryModal = function(options) {
        var opts = $.extend({}, $.fn.svProductCategoryModal.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            var categoryId;

            $element.dialog({
                autoOpen: false,
                width: 750,
                height: 370,
                modal: true,
                open: function() {

                }
            });

            function resetForm() {
                $('form', $element).each(function() { this.reset() });
            }

            function closeDialog() {
                $element.dialog('close');
                resetForm();
            }

            var uploadLinkInit = false;
            var imageList = $('.imagelist', $element[0]);
            $element.bind('openforcategory', function(event, id) {
                categoryId = id;
                resetForm();
                $.ajax({
                    url: 'productcatalogue_json_category.asp',
                    data: { productCategoryId: categoryId },
                    dataType: 'json',
                    success: function(data, textResponse) {
                        $('input[name=name]', $element[0]).val(data.name);
                        $('input[name=productCategoryId]', $element[0]).val(data.itemId);
                        $('textarea[name=description]', $element).val(data.description);
                        $.ajax({
                            url: 'productcatalogue_category_images.asp',
                            data: { productCategoryId: categoryId },
                            success: function(data, textStatus) {
                                imageList.html(data);
                            },
                            complete: function() {
                                $element.dialog('open');
                                if (!uploadLinkInit) {
                                    $('a#uploadcategoryimagelink', $element[0]).productImageManager({
                                        asyncDelete: false,
                                        removeHandle: 'a.removeproductimage',
                                        uploadURL: 'productcatalogue_category_image_upload.asp',
                                        container: imageList,
                                        params: { dataType: 'html' }
                                    });
                                    uploadLinkInit = true;
                                }
                            }
                        });
                    }
                });
            });

            $('a.cancel', $element[0]).click(function() {
                closeDialog();

                return false;
            });

            $('a.save', $element[0]).click(function() {
                var $form = $('form', $element[0]);
                $form.validate();
                if ($form.valid()) {
                    var image_list = "";
                    $('.imageadmin_container', imageList[0]).each(function() {
                        if (image_list != "") image_list += ",";
                        image_list += this.id.replace(/image_/, '');
                    });
                    $('input[name=images]', $element[0]).val(image_list);
                    url = $form.attr('action');
                    $.ajax({
                        data: $form.serialize(),
                        url: url,
                        type: 'POST',
                        success: function(data, textStatus) {
                            opts.onSuccess(data);
                            closeDialog();
                        },
                        dataType: 'html'
                    });
                }
                return false;
            });
        });
    };

    $.fn.svProductCategoryModal.defaults = {
        onSuccess: function(entityTypeId, entityId) { }
    };
})(jQuery);

(function($) {
    $.fn.svCourseLinkPopUp = function(options) {
        var opts = $.extend({}, $.fn.svCourseLinkPopUp.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            $element.svLinkPopUp(opts);
        });
    };

    $.fn.svCourseLinkPopUp.defaults = {
        url: 'training_coursepopup.asp',
        data: function($element) { return { courseId: $element.metadata().id} }
    };
})(jQuery);

$(function() {
    $('a.course').livequery(function() {
        $(this).svCourseLinkPopUp();
    });
});

(function($) {
    $.fn.svCourseOfferingLinkPopUp = function(options) {
        var opts = $.extend({}, $.fn.svCourseOfferingLinkPopUp.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            $element.svLinkPopUp(opts);
        });
    };

    $.fn.svCourseOfferingLinkPopUp.defaults = {
        url: 'training_courseofferingpopup.asp',
        data: function($element) { return { courseOfferingId: $element.metadata().id} }
    };
})(jQuery);

(function($) {
    $.fn.svAutocomplete = function(options) {
        var opts = $.extend({}, $.fn.svAutocomplete.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            $element.autocomplete(opts.url, opts)
				.result(opts.result)
				.onchange(opts.onchange);

            $element.bind('reset', function() {
                $element.val('');
                $element.trigger('setResult', [0, '', '']);
            });

            var setResult = function(e, id, code, name, haltOnSet) {
                $element.data('id', id);
                $element.data('code', code);
                $element.data('name', name);               
                if (parseInt(id) > 0) {
                    $element.addClass('autocomplete_selected');
                }
                else {
                    $element.removeClass('autocomplete_selected');
                }
                $('input[name=' + $element.attr('name').replace(/_text/, '') + ']').val(id);
                if (!haltOnSet) {
                    opts.onSet(id, code, name);
                }
            };

            $element.bind('setResult', setResult);
        });
    };

    $.fn.svAutocomplete.defaults = {
        minChars: 2,
        selectFirst: false,
        highlight: function(value, term) {
            var terms = term.split(' ');
            var highlitvalue = value;
            $.each(terms, function(i, val) {
                highlitvalue = highlitvalue.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + val.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
            });
            return highlitvalue;
        },
        filters: function() { return ''; },
        extraParams: { params: function() { } },
        onSuccess: function() { },
        onSet: function() { }
    };
})(jQuery);

(function($) {
    $.fn.svContractAutocomplete = function(options) {
        var opts = $.extend({}, $.fn.svContractAutocomplete.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            var showContractLookup = function() {
            $('<div />').svContractLookupModal({ query: $element.val(), extraParams: opts.extraParams, onSelect: function(id, code, name) { $element.val("(" + code + ") " + name); $element.trigger('setResult', [id, code, name]); opts.onSet(); } });
            };

            if (opts.allowLookup) {
                $element.after($('<input type=\"button\" value=\"Lookup\" />').click(showContractLookup));
            }

            $element.svAutocomplete(opts);
        });
    };

    var CONTRACT_ID = 0;
    var CONTRACT_CODE = 1;
    var CONTRACT_NAME = 2;

    $.fn.svContractAutocomplete.defaults = {
        url: 'contracts_ContractAutocomplete.asp',
        result: function(e, data, formatted) {
            var id = data[CONTRACT_ID];
            var code = data[CONTRACT_CODE];
            var name = data[CONTRACT_NAME];
            $(e.target).trigger('setResult', [id, code, '(' + code + ') ' + name]);
        },
        onchange: function(e) {
            $(e.target).trigger('setResult', [0, '', '']);
        },
        formatItem: function(data, i, total, value) {
            var item = '';
            var id = data[CONTRACT_ID];
            var code = data[CONTRACT_CODE];
            var name = data[CONTRACT_NAME];
            item += '<span class=\'name\'>'
            item += '(' + code + ') ' + name;
            item += '</span>';

            return item;
        },
        formatResult: function(data, i, total, value) {
            var name = '';
            name += '(' + data[CONTRACT_CODE] + ') ' + data[CONTRACT_NAME];
            return name;
        },
        includeCodeInResult: false,
        allowLookup: true,
        filters: function() { return ''; },
        extraParams: { allcontracts: true },
        onSuccess: function() { },
        onSet: function() { }
    };
})(jQuery);

(function($) {
    $.fn.svProductModal = function(options) {
        var opts = $.extend({}, $.fn.svProductModal.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            $element.svProductHeaderForm();

            var form = $('form', $element[0]);
            form.validate();

            var theDialog = $element.dialog({
                autoOpen: false,
                modal: true,
                overlay: {
                    opacity: 0.5,
                    background: "black"
                },
                height: 370,
                width: 750,
                open: function() { form.get(0).reset(); }
            });

            $('a.save', $element).click(function() {
                var button = $(this);

                var success = function(data, textStatus) {
                    theDialog.dialog('close');
                    opts.onSuccess(data, textStatus);
                };

                var error = function() { alert('There was a problem saving the product. Please try again.'); };
                var complete = function() { button.html('save'); };

                if (form.valid() && button.html() == 'save') {
                    button.html('saving...');
                    $.ajax({
                        url: form.attr('action'),
                        data: form.serialize(),
                        dataType: 'json',
                        success: success,
                        error: error,
                        complete: complete,
                        type: 'POST'
                    });
                }

                return false;
            });

            $('a.cancel', $element).click(function() { theDialog.dialog('close'); return false; });

            $element.bind("open", function(e, name, callback) {
                opts.onSuccess = callback;
                theDialog.dialog('open');
                $('input[name=name]', $element[0]).val(name);
            });
        });
    };

    $.fn.svProductModal.defaults = {
        onSuccess: function() { }
    };
})(jQuery);

(function($) {
    $.fn.svProductHeaderForm = function(options) {
        var opts = $.extend({}, $.fn.svProductHeaderForm.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            var classSelections = $('#categorySelection').svMasterSelectBox({
                idMasterSelect: 'categoryId',
                idSlaveSelect: 'subcategoryId',
                idOptionHolder: 'optionHolder'
            });

            $('#supplierId', $element).svCompanyAutocomplete();

            $('#brandId', $element).dxCombobox();
            $('#categoryId', $element).dxCombobox();
            $('#subcategoryId', $element).dxCombobox();
        });
    };

    $.fn.svProductHeaderForm.defaults = {};
})(jQuery);

(function($) {
    $.fn.svRoomAutocomplete = function(options) {
        var opts = $.extend({}, $.fn.svRoomAutocomplete.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            var showRoomLookup = function() {
                $('<div />').svRoomLookupModal({ query: $element.val(), extraParams: opts.extraParams, onSelect: function(id, code, name) { $element.val(name); $element.trigger('setResult', [id, code, name]); } });
            };

            if (opts.allowLookup) {
                $element.after($('<input type=\"button\" value=\"Lookup\" />').click(showRoomLookup));
            }

            opts.formatResult = function(data, i, total, value) {
                var name = '';
                if (opts.includeCodeInResult)
                    name += '(' + data[ROOM_CODE] + ') ';
                name += data[ROOM_NAME];
                return name;
            };

            $element.svAutocomplete(opts);
        });
    };

    var ROOM_ID = 0;
    var ROOM_CODE = 1;
    var ROOM_NAME = 2;

    $.fn.svRoomAutocomplete.defaults = {
        url: 'contactmanager_roomAutocomplete.asp',
        result: function(e, data, formatted) {
            var id = data[ROOM_ID];
            var code = data[ROOM_CODE];
            var name = data[ROOM_NAME];
            $(e.target).trigger('setResult', [id, code, name]);
        },
        onchange: function(e) {
            $(e.target).trigger('setResult', [0, '', '']);
        },
        formatItem: function(data, i, total, value) {
            var item = '';
            var id = data[ROOM_ID];
            var code = data[ROOM_CODE];
            var name = data[ROOM_NAME];
            item += '<span class=\'name\'>'
            item += name;
            item += '</span>';

            return item;
        },
        includeCodeInResult: false,
        allowLookup: true,
        filters: function() { return ''; },
        extraParams: { params: function() { return 'eggs'; } }
    };
})(jQuery);

(function($) {
    $.fn.svLookupModal = function(options) {
        options = $.extend({
            query: '',
            onSelect: function(id, code, name) { },
            selectableClass: '',
            title: '',
            url: '',
            additionalSelectors: [],
            onSetup: function($element) { }
        }, options);
        return new $.LookupModal(this, options);
    };

    $.LookupModal = function(element, options) {
        var $element = $(element);
        var $viewport = $('<div></div>');

        $element.append($viewport);
        $element.dialog({ autoOpen: true, width: 700, height: 450, title: options.title, resizable: true, modal: true });

        function loadPage(url) {
            $viewport.load(url, setupPage);

            function setupPage() {
                $('a', $element).click(function() {
                    var $this = $(this);
                    if ($this.hasClass('uploadimagelink')) {
                        return true;
                    }
                    else if (triggerAdditionalEvent($this)) {
                        return false;
                    }
                    else if (!$this.hasClass(options.selectableClass)) {
                        loadPage($this.attr('href'));
                        return false;
                    }
                    else {
                        var data = $this.metadata()
                        options.onSelect(data.id, data.code, data.name);
                        $element.dialog('close');
                        return false;
                    }

                });

                function triggerAdditionalEvent(obj) {
                    var eventTriggered = false;

                    $.each(options.additionalSelectors, function() {
                        if (obj.hasClass(this.selectableClass)) {
                            var data = obj.metadata();
                            this.onSelect(data.id, data.code, data.name);
                            eventTriggered = true;
                        }
                    });

                    return eventTriggered;
                }

                $('form', $element).submit(function() {
                    var action;
                    if (this.action.indexOf('?') > 0) {
                        action = this.action.substr(0, this.action.indexOf('?'));
                    }
                    else {
                        action = this.action;
                    }
                    action += '?' + $(this).serialize()
                    loadPage(action);
                    return false;
                });

                $('input[type=button], button[name=reset]', $element).attr('onclick', '').click(function() {
                    loadPage(this.form.action.substr(0, this.form.action.indexOf('?')));
                    return false;
                });

                $('ul.jd_menu', $element).jdMenu();

                $element.css({ padding: '0px' });
                $viewport.css({ height: 417, overflow: 'auto', padding: '5px' });

                options.onSetup($element);
            }
        }

        var extraParams = 'savefilters=false&q=' + escape(options.query);
        $.each(options.extraParams, function(key, param) {
            extraParams += '&' + key + '=' + (typeof param == "function" ? param() : param);
        });

        loadPage(options.url + '?' + extraParams);
    };
})(jQuery);
(function($) {
    $.fn.svContractLookupModal = function(options) {
        options = $.extend({
            query: '',
            onSelect: function(id, code, name) { }
        }, options);
        return new $.ContractLookupModal(this, options);
    };

    $.ContractLookupModal = function(element, options) {
        var $element = $(element);

        $element.svLookupModal({
            query: options.query,
            onSelect: options.onSelect,
            selectableClass: 'contract',
            title: 'Lookup Contract',
            url: 'contracts_lookupContracts.asp',
            extraParams: options.extraParams
        });
    };
})(jQuery);
(function($) {
    $.fn.svProductLookupModal = function(options) {
        options = $.extend({
            query: '',
            onSelect: function(id, code, name) { }
        }, options);
        return new $.ProductLookupModal(this, options);
    };

    $.ProductLookupModal = function(element, options) {
        var $element = $(element);
        $element.svLookupModal({
            query: options.query,
            onSelect: options.onSelect,
            selectableClass: 'product',
            title: 'Lookup Product',
            url: 'productmanager_lookupProducts.asp',
            extraParams: options.extraParams
        });
    };
})(jQuery);
(function($) {
    $.fn.svRoomLookupModal = function(options) {
        options = $.extend({
            query: '',
            onSelect: function(id, code, name) { }
        }, options);
        return new $.RoomLookupModal(this, options);
    };

    $.RoomLookupModal = function(element, options) {
        var $element = $(element);

        function success(id, code, name) {
            options.onSelect(id, code, name);
            $element.dialog('close');
        }

        $element.svLookupModal({
            query: options.query,
            onSelect: options.onSelect,
            selectableClass: 'room',
            title: 'Lookup Room',
            url: 'contactmanager_lookupRoom.asp',
            extraParams: options.extraParams,
            additionalSelectors: [{
                selectableClass: 'organisation',
                onSelect: function(id, code, name) {
                    $('<div />').svOrganisationRoomSelector({
                        organisationId: id,
                        onSelect: success
                    });
                    return false;
                }
            },

                {
                    selectableClass: 'uploadimagelink',
                    onSelect: function() {
                        return false;
                    }
                },
                {
                    selectableClass: 'save',
                    onSelect: function() {
                        return false;
                    } }],
            onSetup: function(page) {
                var roomdetailsectionedit = $('#roomdetailsection-edit', page);
                if (roomdetailsectionedit.length != 0) {
                    roomdetailsectionedit.svRoomHeaderForm();
                    var saving = false;
                    var form = $('form', roomdetailsectionedit);
                    form.validate();
                    roomdetailsectionedit.trigger('show');

                    function organisationExists() {
                        var compIdField = $('input[name=organisationId]', form);
                        var compNameField = $('input[name=organisationId_text]', form);
                        if (compIdField.val() == '0' && compNameField.val() != '') {
                            var company_dialog = $('#createcompanymodal');
                            company_dialog.svCreateCompanyModal({
                                onSuccess: function(compId, compName) {
                                    if (compId > 0) {
                                        compIdField.val(compId);
                                        compNameField.val(compName);
                                    }
                                    company_dialog.dialog('close');
                                    submitForm();
                                    return true;
                                }
                            });
                            var quickcompform = company_dialog.find('form');
                            quickcompform.find('input.name').val(compNameField.val());
                            company_dialog.dialog("open");
                            return false;
                        }
                        else {
                            return true;
                        }
                    }

                    function submitForm() {
                        if (form.valid() && !saving && organisationExists()) {
                            saving = true;
                            $.ajax({
                                url: form.attr('action'),
                                data: form.serialize(),
                                complete: function() {
                                    savebutton.html('save');
                                    saving = false;
                                },
                                success: function(data, textStatus) {
                                    if (data) {
                                        success(data.id, '', data.name);
                                    }
                                },
                                dataType: 'json',
                                type: 'post'
                            });
                        }
                        return false;
                    }

                    var savebutton = $('a.save').click(submitForm);


                }
            }
        });
    };
})(jQuery);
(function($) {
    $.fn.svCourseMaterialsEditor = function(options) {
        options = $.extend({
    }, options);

    return new $.CourseMaterialsEditor(this, options);
};

$.CourseMaterialsEditor = function(element, options) {
    var $element = $(element);

    var deleteNewRows = function() {
        $('tr', element).each(function() {
            if ($(this).data('new') == 'true') $(this).remove();
        });
        return false;
    };

    var deleteRow = function() {
        $(this).parents('tr').remove();
        return false;
    };

    var appendRow = function(docMasterId, isRestricted, docLink, courseId) {
        var row = createRow(docMasterId, isRestricted, docLink, courseId);
        row.data('new', 'true');
        $('tr.newcoursematerialsrow', element).before(row);
    };

    var createRow = function(docMasterId, isRestricted, docLink, courseId) {
        var documentColumn = createDocumentColumn(docMasterId, isRestricted, docLink, courseId);
        var isRestrictedColumn = createIsRestrictedColumn(docMasterId, isRestricted, docLink, courseId);
        var removeColumn = createRemoveColumn();
        var row = $('<tr></tr>').append(documentColumn).append(isRestrictedColumn).append(removeColumn);
        row.addClass('courseMaterialsRow');
        return row;
    };

    var createDocumentColumn = function(docMasterId, isRestricted, docLink, courseId) {
        var col = $('<td>' + docLink + '</td>');
        return col;
    };

    var createIsRestrictedColumn = function(docMasterId, isRestricted, docLink, courseId) {
        var checkbox = '<input type=\"checkbox\"';
        if (isRestricted) checkbox += 'checked=\"checked\"';
        checkbox += 'name=\"isRestricted_' + docMasterId + '\" id=\"isRestricted_' + docMasterId + '\" \/>'
        var hiddeninput = '<input type=\"hidden\" name=\"hiddenisRestricted_' + docMasterId + '\"  value=\"' + docMasterId + '|' + isRestricted + '\" \/>'
        var col = $('<td>' + checkbox + hiddeninput + '</td>');
        return col;
    };

    var createRemoveColumn = function() {
        var removelink = $('<a class="remove button" href=\"#\">remove</a>');
        removelink.click(deleteRow);
        var col = $('<td></td>').append(removelink);
        return col;
    };

    var resetEditor = function() {
        $('tr.courseMaterialRow').each(function() {
            var tr = $(this);
            tr.remove();
        });
    };

    var documentSelector = $('input.document', element).svDocumentAutocomplete();

    $('.addnewcoursematerial', element).click(function() {
        $('#errAdd').text('');
        var docMasterId = documentSelector.data('id')
        var isRestrictedHolder = $(this).parents('tr').find("input[name=isRestricted]");
        var isRestricted = isRestrictedHolder.attr("checked");
        var courseId = $("input[name=courseId]", element).attr("value");
        var docLink;
        if (docMasterId != 0) {
            $.ajax({
                url: 'training_json_courseMaterialLink.asp?docMasterId=' + docMasterId,
                success: function(data, textStatus) {
                    docLink = data.docLink;
                    if (docLink.length == 0) {
                        $('#errAdd').text('Sorry, that document cannot be found');
                    }
                    else if ($('input[name=isRestricted_' + docMasterId + ']').length > 0) {
                        $('#errAdd').text('Document cannot be added more than once.');
                    }
                    else {
                        appendRow(docMasterId, isRestricted, docLink, courseId);
                    }
                    documentSelector.trigger('reset');
                    isRestrictedHolder.removeAttr("checked");
                },
                dataType: 'json'
            });
        }
        else {
            $('#errAdd').text('Please select a document.');
        }
        return false;
    });

    $('a.remove', element).click(deleteRow);
    $('a.cancel_edit').click(deleteNewRows);

    element.bind('reset', function() {
        resetEditor();
    });

    $('input[name^=isRestricted_]').click(function() {
        var docMasterId = $(this).attr("name").replace('isRestricted_', '');
        var isRestricted = $(this).attr('checked');
        $(this).parents('tr').find("input[name^=hiddenisRestricted]").attr("value", docMasterId + '|' + isRestricted);
    });
};
})(jQuery);

(function($) {
    $.fn.svResponseFormWidgetControl = function(options) {
        var opts = $.extend({}, $.fn.svResponseFormWidgetControl.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            var itemsList = $('fieldset.formitems > ol', $element);
            var itemCount = $('li', itemsList).length;
            var itemPicker = $('select.itempicker', $element);

            $('a.removeitem', $element).click(removeItem);

            $('a.additem', $element).click(function() {
                itemCount++;

                var newItem = $('<li />');
                newItem.append(itemPicker.clone().attr('name', 'itemtype_' + itemCount).val(itemPicker.val()));
                newItem.append($('<input type=\'text\' />').attr('name', 'name_' + itemCount));
                newItem.append($('<input type=\'text\' />').attr('name', 'options_' + itemCount));
                newItem.append($('<input type=\'checkbox\' />').attr('name', 'required_' + itemCount));
                newItem.append($('<a />').attr('href', '#').addClass('removeitem').html('x').click(removeItem));
                itemsList.append(newItem);
                itemPicker.val(0);
                return false;
            });

            $element.svWidgetControl(opts);

            function removeItem() {
                var $this = $(this);
                $this.parent('li').remove();
                return false;
            }
        });
    };

    $.fn.svResponseFormWidgetControl.defaults = {};
})(jQuery);
(function($) {
    $.fn.svOrganisationRoomSelector = function(options) {
        options = $.extend({
            caller: null,
            organisationId: null,
            onSelect: function(id, code, name) { }
        }, options);
        return new $.OrganisationRoomSelector(this, options);
    };

    $.OrganisationRoomSelector = function(element, options) {
        var $element = $(element);
        var $viewport = $('<div></div>');

        $element.append($viewport);
        $element.dialog({ autoOpen: true, width: 400, height: 200, title: 'Select Room', resizable: true });

        function loadPage(url) {
            $viewport.load(url, setupPage);

            function setupPage() {

                $('form', $element).submit(function() {
                    var selected = $('input:radio:checked', this);
                    if (selected.length > 0) {
                        options.onSelect(selected.val(), '', $('label', selected.parent('li')).html());
                        $element.dialog('close');
                    }
                    return false;
                });


                $element.css({ padding: '0px' });
                $viewport.css({ height: 317, overflow: 'auto', padding: '5px' });

                $('a.cancel', $element).click(function() {
                    $element.dialog('close');
                    return false;
                });
            }
        }
        loadPage('contactmanager_organisationRoomSelector.asp?compId=' + options.organisationId);
    };
})(jQuery);
(function($) {
    $.fn.svRoomHeaderForm = function(options) {
        var opts = $.extend({}, $.fn.svRoomHeaderForm.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            $('input.companyAutocomplete').svCompanyAutocomplete();

            var initupload = false;
            var imageList = $('div.imagelist', $element);
            
            $element.bind('show', function() {
                $element.show();
                if (!initupload) {
                    $('a.uploadimagelink', $element).productImageManager({
                        asyncDelete: false,
                        removeHandle: 'a.removeimage',
                        allowMultiple:false,
                        uploadURL: 'contactmanager_room_image_upload.asp',
                        container: imageList,
                        params: { dataType: 'html' }
                    });
                    initupload = true;
                }

            });
        });
    };

    $.fn.svRoomHeaderForm.defaults = {};
})(jQuery);

(function($) {
    $.fn.svRoomEditableSection = function(options) {
        var opts = $.extend({}, $.fn.svRoomEditableSection.defaults, options);

        return this.each(function() {
            var $element = $(this);
            var thisopts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            var editor;

            function setupForm() {
                editor = $('#' + $element.attr('id') + '-edit').svRoomHeaderForm();

                var editbutton = $('a.edit_section', $element).hide();
                $element.hover(function() {
                    editbutton.show();
                },
                    function() {
                        editbutton.hide();
                    });
            }

            var onSuccess = thisopts.onSuccess;
            thisopts.onSuccess = function(data, textStatus) {
                setupForm();
                onSuccess(data, textStatus);
            };

            setupForm();

            var onEditable = thisopts.onEditable;
            thisopts.onEditable = function() {
                onEditable();
                editor.trigger('show');
            };

            $element.svEditableSection(thisopts);
        });
    };

    $.fn.svRoomEditableSection.defaults = {
        onSuccess: function() { },
        onEditable: function() {

        }
    };
})(jQuery);

(function($) {
    $.fn.svModal = function(options) {
        var opts = $.extend({}, $.fn.svModal.defaults, options);

        return this.each(function() {
            var $element = $(this);
            var $viewport = $('<div style="overflow-y: auto;height: ' + (opts.height - 33) + 'px;width:' + (opts.width - 5) + 'px;" />');

            $element.append($viewport);
            $element.dialog({ autoOpen: true, width: opts.width, height: opts.height, title: opts.title, resizable: true, modal: true });


            if (opts.url != '')
                $viewport.load(opts.url);
        });
    };

    $.fn.svModal.defaults = {
        title: '',
        width: 400,
        height: 500,
        url: ''
    };
})(jQuery);

(function($) {
    $.fn.svDocumentAutocomplete = function(options) {
        var opts = $.extend({}, $.fn.svDocumentAutocomplete.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            var showDocumentLookup = function() {
                $('<div />').svDocumentLookupModal({ query: $element.val(), extraParams: opts.extraParams, onSelect: function(id, code, name) { $element.val(name); $element.trigger('setResult', [id, code, name]); } });
            };

            if (opts.allowLookup) {
                $element.after($('<input type=\"button\" value=\"Lookup\" />').click(showDocumentLookup));
            }

            opts.formatResult = function(data, i, total, value) {
                var name = '';
                name += data[DOCUMENT_NAME];
                return name;
            };

            $element.svAutocomplete(opts);
        });
    };

    var DOCUMENT_ID = 0;
    var DOCUMENT_NAME = 1;
    var DOCUMENT_SUMMARY = 2;

    $.fn.svDocumentAutocomplete.defaults = {
        url: 'docrep_DocumentAutocomplete.asp',
        result: function(e, data, formatted) {
            var id = data[DOCUMENT_ID];
            var code = '';
            var name = data[DOCUMENT_NAME];
            $(e.target).trigger('setResult', [id, code, name]);
        },
        onchange: function(e) {
            $(e.target).trigger('setResult', [0, '', '']);
        },
        formatItem: function(data, i, total, value) {
            var item = '';
            var id = data[DOCUMENT_ID];
            var code = '';
            var name = data[DOCUMENT_NAME];
            item += '<span class=\'name\'>'
            item += name;
            item += '</span>';

            return item;
        },
        allowLookup: true,
        filters: function() { return ''; },
        extraParams: { clearfilters: 'true' }
    };
})(jQuery);

(function($) {
    $.fn.svDocumentLookupModal = function(options) {
        options = $.extend({
            query: '',
            onSelect: function(id, code, name) { }
        }, options);
        return new $.DocumentLookupModal(this, options);
    };

    $.DocumentLookupModal = function(element, options) {
        var $element = $(element);

        $element.svLookupModal({
            query: options.query,
            onSelect: options.onSelect,
            selectableClass: 'document',
            title: 'Lookup Document',
            url: 'docrep_lookupDocuments.asp',
            extraParams: options.extraParams
        });
    };
})(jQuery);
(function($) {
    $.svOKCancelDialogue = function(options) {
        options = $.extend({}, $.fn.svOKCancelDialogueDefaults, options);

        var textContainer = $('<div />').addClass('sv-dialogue-text').html(options.text);

        var OKButton = $('<a href=\"#\" />')
            .html('OK')
            .addClass('sv-dialogue-ok linkbutton')
            .click(function() {
                options.OK();
                dialogue.dialog('close');
                return false;
            });

        var cancelButton = $('<a href=\"#\" />')
            .html('Cancel')
            .addClass('sv-dialogue-cancel')
            .click(function() {
                dialogue.dialog('close');
                return false;
            });

        var actionRow = $('<div />')
            .addClass('sv-dialogue-actionrow')
            .append(OKButton)
            .append(cancelButton);

        var dialogue = $('<div />')
            .addClass('sv-dialogue')
            .append(textContainer)
            .append(actionRow)
            .dialog({
                autoOpen: true,
                modal: true,
                title: options.title,
                height: options.height,
                width: options.width
            });

    };

    $.fn.svOKCancelDialogueDefaults = {
        title: '',
        text: '',
        height: 135,
        width: 300,
        OK: function() { }
    };
})(jQuery);
(function($) {
    $.fn.svExportToPersonListModal = function(options) {
        var opts = $.extend({}, $.fn.svExportToPersonListModal.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            var modal = $('div.exporttopersonlistmodal').dialog({
                autoOpen: true,
                width: 450,
                height: 175,
                title: 'Export to list',
                modal: true
            });

            var form = $('form', modal);


            $('input:radio', modal).change(enableItems);

            function enableItems() {
                var type = $('input:radio:checked', modal).attr('id').replace(/exportto_/, '');
                if (type == 'existinglist') {
                    $('select.existinglist').attr('disabled', '');
                    $('input.newlist').attr('disabled', 'disabled');
                }
                else {
                    $('select.existinglist').attr('disabled', 'disabled');
                    $('input.newlist').attr('disabled', '');
                }
            }

            function reset() {
                $('div.actionresponse', modal).hide();
                form[0].reset();
            }

            $('a.close', modal).click(function() {
                modal.dialog('close');
                reset();
                return false;
            });

            $('a.ok', modal).click(function() {
                var $button = $(this);
                if ($button.html() != 'Please wait...') {
                    var originalHtml = $button.html();
                    $('div.actionresponse', modal).hide();
                    $button.html('Please wait...');
                    $.ajax({
                        url: form.attr('action'),
                        data: form.serialize(),
                        complete: function() {
                            $button.html(originalHtml);
                        },
                        success: function() {
                            $('div.success', modal).show();
                        },
                        error: function() {
                            $('div.error', modal).show();
                        },
                        dataType: 'html',
                        type: 'post'
                    });
                }
                return false;
            });

            enableItems();
        });
    };

    $.fn.svExportToPersonListModal.defaults = {
        type: '',
        id: null,
        url: 'contactmanager_exporttolist_modal.asp'
    };
})(jQuery);

(function($) {
    $.fn.svContractHeaderEditableSection = function(options) {
        var opts = $.extend({}, $.fn.svContractHeaderEditableSection.defaults, options);

        return this.each(function() {
            var $element = $(this);
            var thisopts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            var editor;

            function setupForm() {
                editor = $('#' + $element.attr('id') + '-edit');
                $('input.primaryParty', editor).svCompanyAutocomplete();
            }

            var onSuccess = thisopts.onSuccess;
            thisopts.onSuccess = function(data, textStatus) {
                setupForm();
                onSuccess(data, textStatus);
            };

            setupForm();

            var onEditable = thisopts.onEditable;
            thisopts.onEditable = function() {
                onEditable();
            };

            var isShortCodeUniqueInContract = function(value, element, param) {
                var isUnique = true;

                if (value != '') {
                    $.ajax({
                        url: 'contracts_json_checkshortcodeisuniqueforcontract.asp?contractId=' + (element.form.contractId.value) + '&shortcode=' + value,
                        success: function(data, textStatus) { isUnique = data; },
                        dataType: 'json',
                        async: false
                    });
                }

                return isUnique;
            };

            $.validator.addMethod('uniqueShortCode', isShortCodeUniqueInContract, 'That short code is already in use. Please try another.');

            $element.svEditableSection(thisopts);
        });
    };

    $.fn.svContractHeaderEditableSection.defaults = {
        onSuccess: function() { },
        onEditable: function() {

        },
        customValidation: {
            rules: {
                code: {
                    uniqueShortCode: true
                }
            }
        }
    };
})(jQuery);

(function($) {
    $.fn.svOrganisationHeader = function(options) {
        options = $.extend({
            onSuccess: function() { return true; },
            warnOnExit: true,
            action: 'EDIT',
            dataType: 'html',
            submitStyle: 'async'
        }, options);

        return new $.OrganisationHeader(this, options);
    };

    $.OrganisationHeader = function(element, options) {
        var $element = $(element);

        var isShortCodeUnique = function(value, element, param) {
            var isUnique = true;

            if (value != '') {
                $.ajax({
                    url: 'contactmanager_json_checkorganisationshortcodeisunique.asp?compId=' + element.form.compId.value + '&shortcode=' + value,
                    success: function(data, textStatus) { isUnique = data; },
                    dataType: 'json',
                    async: false
                });
            }

            return isUnique;
        };

        $.validator.addMethod('uniqueShortCode', isShortCodeUnique, 'That short code is already in use. Please try another.');

        var organisationDetailsSection = $('#organisationDetailsSection').svEditableSection({
            customValidation: {
                rules: {
                    shortCode: {
                        uniqueShortCode: true
                    }
                }
            },
            onSuccess: function(response, textStatus) {
                options.onSuccess(response, textStatus);
            },
            warnOnExit: options.warnOnExit,
            action: options.action,
            dataType: options.dataType,
            submitStyle: options.submitStyle
        });
    };

})(jQuery);
(function($) {
    $.fn.svWarningProductsModal = function(options) {
        var opts = $.extend({}, $.fn.svWarningProductsModal.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            $element.dialog({
                autoOpen: false,
                width: 450,
                height: 355,
                modal: true
            });

            var form = $('form', $element);

            $('a.ok', $element).click(function() {
                var doAction = $('input[name=doAction]:checked', $element).val();
                if (doAction == 'ignore')
                    opts.ignore();
                else if (doAction == 'removeProject')
                    opts.removeProject();
                else if (doAction == 'cancel')
                    opts.cancel();

                $element.dialog('close');
                form[0].reset();
                return false;
            });
        });
    };

    $.fn.svWarningProductsModal.defaults = {
        ignore: function() { },
        removeProject: function() { },
        cancel: function() { }
    };
})(jQuery);

(function($) {
    $.fn.svInvalidProductsModal = function(options) {
        var opts = $.extend({}, $.fn.svInvalidProductsModal.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({}, opts, $element.metadata()) : opts;

            $element.dialog({
                autoOpen: false,
                width: 450,
                height: 150,
                modal: true
            });

            var form = $('form', $element);

            $('a.ok', $element).click(function() {
                var doAction = $('input[name=doAction]:checked', $element).val();
                if (doAction == 'ignore')
                    opts.ignore();
                else if (doAction == 'removeProject')
                    opts.removeProject();
                else if (doAction == 'cancel')
                    opts.cancel();

                $element.dialog('close');
                form[0].reset();
                return false;
            });
        });
    };

    $.fn.svInvalidProductsModal.defaults = {
        ignore: function() { },
        removeProject: function() { },
        cancel: function() { }
    };
})(jQuery);

(function($) {
    $.fn.svProjectAutocomplete = function(options) {
        var opts = $.extend({}, $.fn.svProjectAutocomplete.defaults, options);

        return this.each(function() {
            var $element = $(this);
            opts = $.metadata ? $.extend({
                extraParams: {
                    contractId: function() {
                        return $(opts.rootContractSelector).data('id');
                    }
                },
                result: function(e, data, formatted) {
                    var id = data[CONTRACT_ID];
                    var code = data[CONTRACT_CODE];
                    var name = data[CONTRACT_NAME];
                    $(e.target).trigger('setResult', [id, code, '(' + code + ') ' + name]);
                    //updateRoot(id, code, name);
                }
            }, opts, $element.metadata()) : opts;

            opts.onSet = opts.onSet || function(id, code, name) {
                updateRoot(id, code, name);
            };

            function updateRoot(id, code, name) {
                $.ajax({
                    url: 'contracts_json_getRootContract.asp',
                    data: { contractId: $element.data('id') },
                    dataType: 'json',
                    success: function(data, textStatus) {
                        var rootAutocomplete = $(opts.rootContractSelector);
                        if (data) {
                            var name = '(' + data.longcode + ') ' + data.longname;
                            rootAutocomplete.trigger('setResult', [data.id, data.code, name, true]);
                            rootAutocomplete.val(name);
                        }
                    }
                });
            }

            var showProjectLookup = function() {
                $('<div />').svProjectLookupModal({ query: $element.val(), extraParams: { contractId: $(opts.rootContractSelector).data('id') }, onSelect: function(id, code, name) { $element.val("(" + code + ") " + name); $element.trigger('setResult', [id, code, name]); updateRoot(id, code, name); opts.onSet(); } });
            };

            if (opts.allowLookup) {
                $element.after($('<input type=\"button\" value=\"Lookup\" />').click(showProjectLookup));
            }

            $element.svAutocomplete(opts);
        });
    };

    var CONTRACT_ID = 0;
    var CONTRACT_CODE = 1;
    var CONTRACT_NAME = 2;

    $.fn.svProjectAutocomplete.defaults = {
        url: 'contracts_ProjectAutocomplete.asp',
        onchange: function(e) {
            $(e.target).trigger('setResult', [0, '', '']);
        },
        formatItem: function(data, i, total, value) {
            var item = '';
            var id = data[CONTRACT_ID];
            var code = data[CONTRACT_CODE];
            var name = data[CONTRACT_NAME];
            item += '<span class=\'name\'>'
            item += '(' + code + ') ' + name;
            item += '</span>';

            return item;
        },
        formatResult: function(data, i, total, value) {
            var name = '';
            name += '(' + data[CONTRACT_CODE] + ') ' + data[CONTRACT_NAME];
            return name;
        },
        includeCodeInResult: false,
        allowLookup: true,
        filters: function() { return ''; },
        onSuccess: function() { },
        onSet: null,
        rootContractSelector: null
    };
})(jQuery);

(function($) {
    $.fn.svProjectLookupModal = function(options) {
        options = $.extend({
            query: '',
            onSelect: function(id, code, name) { }
        }, options);
        return new $.ProjectLookupModal(this, options);
    };

    $.ProjectLookupModal = function(element, options) {
        var $element = $(element);

        $element.svLookupModal({
            query: options.query,
            onSelect: options.onSelect,
            selectableClass: 'contract',
            title: 'Lookup Project',
            url: 'contracts_lookupProjects.asp',
            extraParams: options.extraParams
        });
    };
})(jQuery);
(function($) {
    $.svOKDialogue = function(options) {
        options = $.extend({}, $.fn.svOKDialogueDefaults, options);

        var textContainer = $('<div />').addClass('sv-dialogue-text').html(options.text);

        var OKButton = $('<a href=\"#\" />')
            .html('OK')
            .addClass('sv-dialogue-ok linkbutton')
            .click(function() {
                options.OK();
                dialogue.dialog('close');
                return false;
            });

        var actionRow = $('<div />')
            .addClass('sv-dialogue-actionrow')
            .append(OKButton);


        var dialogue = $('<div />')
            .addClass('sv-dialogue')
            .append(textContainer)
            .append(actionRow)
            .dialog({
                autoOpen: true,
                modal: true,
                title: options.title,
                height: options.height,
                width: options.width
            });

    };

    $.fn.svOKDialogueDefaults = {
        title: '',
        text: '',
        height: 135,
        width: 300,
        OK: function() { }
    };
})(jQuery);
(function($) {
	$.fn.svContractStakeholderManager = function(options) {
		options = $.extend({
			onSuccess:function() {}
		}, options);
		
		return new $.ContractStakeholderManager(this, options);
	};
	
	$.ContractStakeholderManager = function(element, options) {
		var control = element;
		
		var form = control.find('form')[0];
		
		var autocomplete = control.find('input.addPerson').svPersonAutocomplete();
		
		var addButton = control.find('a.addPerson').click(function() {
			var contId = parseInt(form.contId.value);
			var contName = form.person_name.value;
			if (contId <= 0 || isNaN(contId)) {
				var firstname = contName.indexOf(" ") != -1 ? contName.substring(0, contName.indexOf(" ")) : contName;
				var surname = contName.indexOf(" ") != -1 ? contName.substring(contName.indexOf(" ") + 1) : '';
				company_dialog.populateForm({firstname: firstname, surname: surname, compId: form.compId.value, company: form.company.value});
				company_dialog.dialog('open');	
			}
			else {
				addPersonToOrganisation(contId);
			}
			return false;
		});
		
		var addPersonToOrganisation = function(contId) {
			submitForm('add', contId);
		};
		
		var removePerson = function() {
			var contId = $(this).parents('tr').attr('id').replace(/person_/, '');
			submitForm('remove', contId);
			return false;
		};
		
		var submitForm = function(updateFunction, contId) {
			var url = $(form).attr('action');
			form.contId.value = contId;
			var data = $(form).serialize();
			data += "&updateFunction=" + updateFunction;
			$.ajax({
				complete: formUpdateComplete,
				data: data,
				dataType: 'html',
				error: formUpdateError,
				success: formUpdateSuccess,
				type:'POST',
				url: url
			});
		};
		
		var formUpdateError = function(XMLHttpRequest, textStatus, errorThrown) {
			alert('There was a problem while saving. Please try again.');
		};
		
		var formUpdateSuccess = function(data, textStatus) {			
			if ($(data).html() != null)
				options.onSuccess();
			else
				formUpdateError(null, textStatus, null);
		};
		
		var formUpdateComplete = function() {
		}
		
		control.find('a.remove').click(removePerson);
		
		$('tr', control).hover(
			function() {
				$('a.remove', $(this)).show();
			},
			function() {
				$('a.remove', $(this)).hide();
			}
		);
	};
})(jQuery);



		
(function($) {
    $.fn.svDeleteLink = function(options) {
        options = $.extend({}, $.fn.svDeleteLinkDefaults, options);
        
        return this.each(function() {
            var $element = $(this);
            var opts = $.metadata ? $.extend({}, options, $element.metadata()) : options;

            $element.click(function() {
                var form = $(opts.form);
                $.ajax({
                    url: opts.checkUrl,
                    data: { itemId: opts.itemId },
                    dataType: 'json',
                    success: function(data, textStatus) {
                        if (data) {
                            $.svOKCancelDialogue({
                                title: 'Are you sure?',
                                text: 'Are you sure you want to delete this ' + opts.objectName + '?<br /><br />You will not be able to undo this operation.',
                                OK: function() {
                                    form.submit();
                                }
                            });
                        }
                        else {

                            $.svOKDialogue({
                                title: 'Cannot delete ' + opts.objectName,
                                text: 'You cannot delete this ' + opts.objectName + ' as it has data associated with it.',
                                height: 100
                            });
                        }
                    }

                });
                return false;
            });
        });
    };

    $.fn.svDeleteLinkDefaults = {
        checkUrl: '',
        objectName: '',
        itemId: '',
        form: ''
    };
})(jQuery);
/*
 * jdMenu 1.4.1 (2008-03-31)
 *
 * Copyright (c) 2006,2007 Jonathan Sharp (http://jdsharp.us)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://jdsharp.us/
 *
 * Built upon jQuery 1.2.1 (http://jquery.com)
 * This also requires the jQuery dimensions >= 1.2 plugin
 */

// This initializes the menu
$(function() {
	$('ul.jd_menu').jdMenu();
});

(function($) {
    function addEvents(ul) {
        var settings = $.data($(ul).parents().andSelf().filter('ul.jd_menu')[0], 'jdMenuSettings');
        $('> li', ul)
			.bind('mouseenter.jdmenu mouseleave.jdmenu', function(evt) {
			    $(this).toggleClass('jdm_hover');
			    var ul = $('> ul', this);
			    if (ul.length == 1) {
			        clearTimeout(this.$jdTimer);
			        var enter = (evt.type == 'mouseenter');
			        var fn = (enter ? showMenu : hideMenu);
			        this.$jdTimer = setTimeout(function() {
			            fn(ul[0], settings.onAnimate, settings.isVertical);
			        }, enter ? settings.showDelay : settings.hideDelay);
			    }
			})
			.bind('click.jdmenu', function(evt) {
			    var ul = $('> ul', this);

			    if (ul.length == 1 &&
					(settings.disableLinks == true || $(this).hasClass('accessible'))) {
			        showMenu(ul, settings.onAnimate, settings.isVertical);
			        return false;
			    }

			    // if they click a link then follow it!
			    var a;
			    if ($(evt.target).is('a')) {
			        a = evt.target;
			    }
			    else if (evt.target == this) {
			        var link = $('> a', evt.target).not('.accessible');
			        if (link.length > 0) {
			            var a = link[0];
			        }
			    }

			    if (a) {
			        if (!a.onclick) {
			            window.open(a.href, a.target || '_self');
			        } else {
			            $(a).trigger('click');
			        }
			    }


			    if (settings.disableLinks ||
					(!settings.disableLinks && !$(this).parent().hasClass('jd_menu'))) {
			        $(this).parent().jdMenuHide();
			        evt.stopPropagation();
			    }

			    return false;
			})
			.find('> a')
				.bind('focus.jdmenu blur.jdmenu', function(evt) {
				    var p = $(this).parents('li:eq(0)');
				    if (evt.type == 'focus') {
				        p.addClass('jdm_hover');
				    } else {
				        p.removeClass('jdm_hover');
				    }
				})
				.filter('.accessible')
					.bind('click.jdmenu', function(evt) {
					    evt.preventDefault();
					});
    }

    function showMenu(ul, animate, vertical) {
        var ul = $(ul);
        if (ul.is(':visible')) {
            return;
        }
        ul.bgiframe();
        var li = ul.parent();
        
        ul.trigger('jdMenuShow')
			.positionBy({ target: li[0],
			    targetPos: (vertical === true || !li.parent().hasClass('jd_menu') ? 1 : 2),
			    elementPos: (vertical === true || !li.parent().hasClass('jd_menu') ? 0 : 1),
			    hideAfterPosition: true,
			    allowResize: true
			});
        if (!ul.hasClass('jdm_events')) {
            ul.addClass('jdm_events');
            addEvents(ul);
        }
        li.addClass('jdm_active')
        // Hide any adjacent menus
			.siblings('li').find('> ul:eq(0):visible')
				.each(function() {
				    hideMenu(this);
				});
        if (animate === undefined) {
            ul.show();
        } else {
            animate.apply(ul[0], [true]);
        }
    }

    function hideMenu(ul, animate) {
        var ul = $(ul);
        $('.bgiframe', ul).remove();
        ul.filter(':not(.jd_menu)')
			.find('> li > ul:eq(0):visible')
				.each(function() {
				    hideMenu(this);
				})
			.end();
        if (animate === undefined) {
            ul.hide()
        } else {
            animate.apply(ul[0], [false]);
        }

        ul.trigger('jdMenuHide')
			.parents('li:eq(0)')
				.removeClass('jdm_active jdm_hover')
			.end()
				.find('> li')
				.removeClass('jdm_active jdm_hover');
    }

    // Public methods
    $.fn.jdMenu = function(settings) {
        // Future settings: activateDelay
        var settings = $.extend({	// Time in ms before menu shows
            showDelay: 200,
            // Time in ms before menu hides
            hideDelay: 500,
            // Should items that contain submenus not 
            // respond to clicks
            disableLinks: false
            // This callback allows for you to animate menus
            //onAnimate:	null
        }, settings);
        if (!$.isFunction(settings.onAnimate)) {
            settings.onAnimate = undefined;
        }
        return this.filter('ul.jd_menu').each(function() {
            $.data(this,
					'jdMenuSettings',
					$.extend({ isVertical: $(this).hasClass('jd_menu_vertical') }, settings)
					);
            addEvents(this);
        });
    };

    $.fn.jdMenuUnbind = function() {
        $('ul.jdm_events', this)
			.unbind('.jdmenu')
			.find('> a').unbind('.jdmenu');
    };
    $.fn.jdMenuHide = function() {
        return this.filter('ul').each(function() {
            hideMenu(this);
        });
    };

    // Private methods and logic
    $(window)
    // Bind a click event to hide all visible menus when the document is clicked
		.bind('click.jdmenu', function() {
		    $('ul.jd_menu ul:visible').jdMenuHide();
		});
})(jQuery);

/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * $LastChangedDate$
 * $Rev$
 *
 * Version 2.1.1
 */

(function($){

/**
 * The bgiframe is chainable and applies the iframe hack to get 
 * around zIndex issues in IE6. It will only apply itself in IE6 
 * and adds a class to the iframe called 'bgiframe'. The iframe
 * is appeneded as the first child of the matched element(s) 
 * with a tabIndex and zIndex of -1.
 * 
 * By default the plugin will take borders, sized with pixel units,
 * into account. If a different unit is used for the border's width,
 * then you will need to use the top and left settings as explained below.
 *
 * NOTICE: This plugin has been reported to cause perfromance problems
 * when used on elements that change properties (like width, height and
 * opacity) a lot in IE6. Most of these problems have been caused by 
 * the expressions used to calculate the elements width, height and 
 * borders. Some have reported it is due to the opacity filter. All 
 * these settings can be changed if needed as explained below.
 *
 * @example $('div').bgiframe();
 * @before <div><p>Paragraph</p></div>
 * @result <div><iframe class="bgiframe".../><p>Paragraph</p></div>
 *
 * @param Map settings Optional settings to configure the iframe.
 * @option String|Number top The iframe must be offset to the top
 * 		by the width of the top border. This should be a negative 
 *      number representing the border-top-width. If a number is 
 * 		is used here, pixels will be assumed. Otherwise, be sure
 *		to specify a unit. An expression could also be used. 
 * 		By default the value is "auto" which will use an expression 
 * 		to get the border-top-width if it is in pixels.
 * @option String|Number left The iframe must be offset to the left
 * 		by the width of the left border. This should be a negative 
 *      number representing the border-left-width. If a number is 
 * 		is used here, pixels will be assumed. Otherwise, be sure
 *		to specify a unit. An expression could also be used. 
 * 		By default the value is "auto" which will use an expression 
 * 		to get the border-left-width if it is in pixels.
 * @option String|Number width This is the width of the iframe. If
 *		a number is used here, pixels will be assume. Otherwise, be sure
 * 		to specify a unit. An experssion could also be used.
 *		By default the value is "auto" which will use an experssion
 * 		to get the offsetWidth.
 * @option String|Number height This is the height of the iframe. If
 *		a number is used here, pixels will be assume. Otherwise, be sure
 * 		to specify a unit. An experssion could also be used.
 *		By default the value is "auto" which will use an experssion
 * 		to get the offsetHeight.
 * @option Boolean opacity This is a boolean representing whether or not
 * 		to use opacity. If set to true, the opacity of 0 is applied. If
 *		set to false, the opacity filter is not applied. Default: true.
 * @option String src This setting is provided so that one could change 
 *		the src of the iframe to whatever they need.
 *		Default: "javascript:false;"
 *
 * @name bgiframe
 * @type jQuery
 * @cat Plugins/bgiframe
 * @author Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
 */
$.fn.bgIframe = $.fn.bgiframe = function(s) {
	// This is only for IE6
	if ( $.browser.msie && /6.0/.test(navigator.userAgent) ) {
		s = $.extend({
			top     : 'auto', // auto == .currentStyle.borderTopWidth
			left    : 'auto', // auto == .currentStyle.borderLeftWidth
			width   : 'auto', // auto == offsetWidth
			height  : 'auto', // auto == offsetHeight
			opacity : true,
			src     : 'javascript:false;'
		}, s || {});
		var prop = function(n){return n&&n.constructor==Number?n+'px':n;},
		    html = '<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+
		               'style="display:block;position:absolute;z-index:-1;'+
			               (s.opacity !== false?'filter:Alpha(Opacity=\'0\');':'')+
					       'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+
					       'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+
					       'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+
					       'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+
					'"/>';
		return this.each(function() {
			if ( $('> iframe.bgiframe', this).length == 0 )
				this.insertBefore( document.createElement(html), this.firstChild );
		});
	}
	return this;
};

})(jQuery);
/* Copyright (c) 2007 Paul Bakaus (paul.bakaus@googlemail.com) and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * $LastChangedDate$
 * $Rev$
 *
 * Version: @VERSION
 *
 * Requires: jQuery 1.2+
 */

(function($){
	
$.dimensions = {
	version: '@VERSION'
};

// Create innerHeight, innerWidth, outerHeight and outerWidth methods
$.each( [ 'Height', 'Width' ], function(i, name){
	
	// innerHeight and innerWidth
	$.fn[ 'inner' + name ] = function() {
		if (!this[0]) return;
		
		var torl = name == 'Height' ? 'Top'    : 'Left',  // top or left
		    borr = name == 'Height' ? 'Bottom' : 'Right'; // bottom or right
		
		return this.is(':visible') ? this[0]['client' + name] : num( this, name.toLowerCase() ) + num(this, 'padding' + torl) + num(this, 'padding' + borr);
	};
	
	// outerHeight and outerWidth
	$.fn[ 'outer' + name ] = function(options) {
		if (!this[0]) return;
		
		var torl = name == 'Height' ? 'Top'    : 'Left',  // top or left
		    borr = name == 'Height' ? 'Bottom' : 'Right'; // bottom or right
		
		options = $.extend({ margin: false }, options || {});
		
		var val = this.is(':visible') ? 
				this[0]['offset' + name] : 
				num( this, name.toLowerCase() )
					+ num(this, 'border' + torl + 'Width') + num(this, 'border' + borr + 'Width')
					+ num(this, 'padding' + torl) + num(this, 'padding' + borr);
		
		return val + (options.margin ? (num(this, 'margin' + torl) + num(this, 'margin' + borr)) : 0);
	};
});

// Create scrollLeft and scrollTop methods
$.each( ['Left', 'Top'], function(i, name) {
	$.fn[ 'scroll' + name ] = function(val) {
		if (!this[0]) return;
		
		return val != undefined ?
		
			// Set the scroll offset
			this.each(function() {
				this == window || this == document ?
					window.scrollTo( 
						name == 'Left' ? val : $(window)[ 'scrollLeft' ](),
						name == 'Top'  ? val : $(window)[ 'scrollTop'  ]()
					) :
					this[ 'scroll' + name ] = val;
			}) :
			
			// Return the scroll offset
			this[0] == window || this[0] == document ?
				self[ (name == 'Left' ? 'pageXOffset' : 'pageYOffset') ] ||
					$.boxModel && document.documentElement[ 'scroll' + name ] ||
					document.body[ 'scroll' + name ] :
				this[0][ 'scroll' + name ];
	};
});

$.fn.extend({
	position: function() {
		var left = 0, top = 0, elem = this[0], offset, parentOffset, offsetParent, results;
		
		if (elem) {
			// Get *real* offsetParent
			offsetParent = this.offsetParent();
			
			// Get correct offsets
			offset       = this.offset();
			parentOffset = offsetParent.offset();
			
			// Subtract element margins
			offset.top  -= num(elem, 'marginTop');
			offset.left -= num(elem, 'marginLeft');
			
			// Add offsetParent borders
			parentOffset.top  += num(offsetParent, 'borderTopWidth');
			parentOffset.left += num(offsetParent, 'borderLeftWidth');
			
			// Subtract the two offsets
			results = {
				top:  offset.top  - parentOffset.top,
				left: offset.left - parentOffset.left
			};
		}
		
		return results;
	},
	
	offsetParent: function() {
		var offsetParent = this[0].offsetParent;
		while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && $.css(offsetParent, 'position') == 'static') )
			offsetParent = offsetParent.offsetParent;
		return $(offsetParent);
	}
});

function num(el, prop) {
	return parseInt($.curCSS(el.jquery?el[0]:el,prop,true))||0;
};

})(jQuery);
/*
* positionBy 1.0.7 (2008-01-29)
*
* Copyright (c) 2006,2007 Jonathan Sharp (http://jdsharp.us)
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
*
* http://jdsharp.us/
*
* Built upon jQuery 1.2.2 (http://jquery.com)
* This also requires the jQuery dimensions plugin
*/
(function($) {

    // Our range object is used in calculating positions
    var Range = function(x1, y1, x2, y2) {
        this.x1 = x1; this.x2 = x2;
        this.y1 = y1; this.y2 = y2;
    };

    Range.prototype.contains = function(range) {
        return (this.x1 <= range.x1 && range.x2 <= this.x2)
				&&
				(this.y1 <= range.y1 && range.y2 <= this.y2);
    };
    Range.prototype.transform = function(x, y) {
        return new Range(this.x1 + x, this.y1 + y, this.x2 + x, this.y2 + y);
    };

    $.fn.positionBy = function(args) {
        var date1 = new Date();
        if (this.length == 0) {
            return this;
        }

        var args = $.extend({	// The target element to position us relative to
            target: null,
            // The target's corner, possible values 0-3
            targetPos: null,
            // The element's corner, possible values 0-3
            elementPos: null,

            // A raw x,y coordinate
            x: null,
            y: null,

            // Pass in an array of positions that are valid 0-15
            positions: null,

            // Add the final position class to the element (eg. positionBy0 through positionBy3, positionBy15)
            addClass: false,

            // Force our element to be at the location we specified (don't try to auto position it)
            force: false,

            // The element that we will make sure our element doesn't go outside of
            container: window,

            // Should the element be hidden after positioning?
            hideAfterPosition: false,

            // added by SV. Allows element to be resized if it is too big for every position.
            allowResize: false
        }, args);

        if (args.x != null) {
            var tLeft = args.x;
            var tTop = args.y;
            var tWidth = 0;
            var tHeight = 0;

            // Position in relation to an element
        } else {
            var $target = $($(args.target)[0]);
            var tWidth = $target.outerWidth();
            var tHeight = $target.outerHeight();
            var tOffset = $target.offset();
            var tLeft = tOffset.left;
            var tTop = tOffset.top;
        }

        // Our target right, bottom coord
        var tRight = tLeft + tWidth;
        var tBottom = tTop + tHeight;

        return this.each(function() {
            var $element = $(this);

            // Position our element in the top left so we can grab its width without triggering scrollbars
            if (!$element.is(':visible')) {
                $element.css({ left: -3000,
                    top: -3000
                })
								.show();
            }

            // Holds a list of alternate positions to try if this one is not in the browser viewport
            var next = setupNexts();
            function setupNexts() {
                var next = [];
                next[0] = [1, 7, 4];
                next[1] = [0, 6, 4];
                next[2] = [1, 3, 10];
                next[3] = [1, 6, 10];
                next[4] = [1, 6, 9];
                next[5] = [6, 4, 9];
                next[6] = [7, 1, 4];
                next[7] = [6, 0, 4];
                next[8] = [7, 9, 4];
                next[9] = [0, 7, 4];
                next[10] = [0, 7, 3];
                next[11] = [0, 10, 3];
                next[12] = [13, 7, 10];
                next[13] = [12, 6, 3];
                next[14] = [15, 1, 4];
                next[15] = [14, 0, 9];
                return next;
            }

            // Holds x1,y1,x2,y2 coordinates for a position in relation to our target element
            var position = setupPositions($element);

            function setupPositions($element) {
                var eWidth = $element.outerWidth();
                var eHeight = $element.outerHeight();

                var position = [];

                position[0] = new Range(tRight, tTop, tRight + eWidth, tTop + eHeight);
                position[1] = new Range(tRight, tBottom - eHeight, tRight + eWidth, tBottom);
                position[2] = new Range(tRight, tBottom, tRight + eWidth, tBottom + eHeight);
                position[3] = new Range(tRight - eWidth, tBottom, tRight, tBottom + eHeight);
                position[4] = new Range(tLeft, tBottom, tLeft + eWidth, tBottom + eHeight);
                position[5] = new Range(tLeft - eWidth, tBottom, tLeft, tBottom + eHeight);
                position[6] = new Range(tLeft - eWidth, tBottom - eHeight, tLeft, tBottom);
                position[7] = new Range(tLeft - eWidth, tTop, tLeft, tTop + eHeight);
                position[8] = new Range(tLeft - eWidth, tTop - eHeight, tLeft, tTop);
                position[9] = new Range(tLeft, tTop - eHeight, tLeft + eWidth, tTop);
                position[10] = new Range(tRight - eWidth, tTop - eHeight, tRight, tTop);
                position[11] = new Range(tRight, tTop - eHeight, tRight + eWidth, tTop);
                position[12] = new Range(tRight - eWidth, tTop, tRight, tTop + eHeight);
                position[13] = new Range(tRight - eWidth, tBottom - eHeight, tRight, tBottom);
                position[14] = new Range(tLeft, tBottom - eHeight, tLeft + eWidth, tBottom);
                position[15] = new Range(tLeft, tTop, tLeft + eWidth, tTop + eHeight);
                return position;
            }



            // Our Positions via ASCII ART
            //
            // 8   9       10   11
            //   +------------+
            // 7 | 15      12 | 0
            //   |            |
            // 6 | 14      13 | 1
            //   +------------+
            // 5   4        3   2

            if (args.positions !== null) {
                var pos = args.positions[0];
            } else if (args.targetPos != null && args.elementPos != null) {
                var pos = [];
                pos[0] = [];
                pos[0][0] = 15;
                pos[0][1] = 7;
                pos[0][2] = 8;
                pos[0][3] = 9;
                pos[1] = [];
                pos[1][0] = 0;
                pos[1][1] = 12;
                pos[1][2] = 10;
                pos[1][3] = 11;
                pos[2] = [];
                pos[2][0] = 2;
                pos[2][1] = 3;
                pos[2][2] = 13;
                pos[2][3] = 1;
                pos[3] = [];
                pos[3][0] = 4;
                pos[3][1] = 5;
                pos[3][2] = 6;
                pos[3][3] = 14;

                var pos = pos[args.targetPos][args.elementPos];
            }

            var ePos = null;
            var fPos = pos;
            var attempts = 0;
            while (!ePos && attempts < 10) {
                ePos = getElementsNewPosition(fPos);
                if (!ePos) {
                    if (args.allowResize) {

			//issue 1932 - remove the ability to use scrolling
                       // $element.css('overflow', 'hidden');
		        //$element.height($element.height() - 50);
                      

                        position = setupPositions($element);
                        if (!$element.hasClass('scrollable')) {
                            $element.addClass('scrollable');
                            var lastY = null;
                            $element.mousemove(function(e) {
                                var elementOffset = $element.offset();
                                if (lastY != null) {
                                    if (e.clientY < lastY) {
                                        if ((elementOffset.top + $element.height()) - e.clientY > 50)
                                            $element.scrollTop($element.scrollTop() - 5);
                                    }
                                    else if (e.clientY > lastY) {
                                        if (e.clientY - elementOffset.top > 50)
                                            $element.scrollTop($element.scrollTop() + 5);
                                    }
                                }
                                lastY = e.clientY;
                                return true;
                            });
                        }
                    }
                    else {
                        ePos = position[fPos];
                    }
                }
                attempts++;
            }

            if (!ePos) {
                ePos = position[fPos];
            }

            function getElementsNewPosition(pos) {
                var ePos = position[pos];
                if (!args.force) {
                    // TODO: Do the args.container
                    // window width & scroll offset
                    $window = $(window);
                    var sx = $window.scrollLeft();
                    var sy = $window.scrollTop();

                    // TODO: Look at innerWidth & innerHeight
                    var container = new Range(sx, sy, sx + $window.width(), sy + $window.height());

                    // If we are outside of our viewport, see if we are outside vertically or horizontally and push onto the stack
                    var stack;
                    if (args.positions) {
                        stack = args.positions;
                    } else {
                        stack = [pos];
                    }
                    var test = []; 	// Keeps track of our positions we already tried

                    while (stack.length > 0) {
                        var p = stack.shift();
                        if (test[p]) {
                            if (stack.length == 0) {
                                return null;
                            }
                            continue;
                        }
                        test[p] = true;
                        // If our current position is not within the viewport (eg. window)
                        // add the next suggested position
                        if (!container.contains(position[p])) {
                            if (args.positions === null) {
                                stack = jQuery.merge(stack, next[p]);
                            }
                        } else {
                            ePos = position[p];
                            break;
                        }
                        if (stack.length == 0) {
                            return null;
                        }
                    }
                }
                return ePos;
            }
            // + TODO: Determine if we are going to use absolute left, top, bottom, right 
            // positions relative to our target

            // Take into account any absolute or fixed positioning
            // to 'normalize' our coordinates
            $element.parents().each(function() {
                var $this = $(this);
                if ($this.css('position') != 'static') {
                    var abs = $this.offset();
                    ePos = ePos.transform(-abs.left, -abs.top);
                    return false;
                }
            });

            // Finally position our element
            var css = { left: ePos.x1, top: ePos.y1 };
            if (args.hideAfterPosition) {
                css['display'] = 'none';
            }
            $element.css(css);

            if (args.addClass) {
                $element.removeClass('positionBy0 positionBy1 positionBy2 positionBy3 positionBy4 positionBy5 '
									+ 'positionBy6 positionBy7 positionBy8 positionBy9 positionBy10 positionBy11 '
									+ 'positionBy12 positionBy13 positionBy14 positionBy15')
						.addClass('positionBy' + p);
            }
        });
    };

})(jQuery);

/*
 * jQuery Impromptu
 * By: Trent Richardson [http://trentrichardson.com]
 * Version 1.8
 * Last Modified: 12/28/2008
 * 
 * Copyright 2008 Trent Richardson
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
jQuery.extend({	
	ImpromptuDefaults: { prefix:'jqi', buttons:{ Ok:true }, loaded:function(){}, submit:function(){return true;}, callback:function(){}, opacity:0.6, zIndex: 999, overlayspeed:'slow', promptspeed:'fast', show:'fadeIn', focus:0, useiframe:false, top: '100px', persistent: true },
	SetImpromptuDefaults: function(o){ 
		jQuery.ImpromptuDefaults = jQuery.extend({},jQuery.ImpromptuDefaults,o);
	},
	prompt: function(m,o){
		o = jQuery.extend({},jQuery.ImpromptuDefaults,o);
		
		var ie6 = (jQuery.browser.msie && jQuery.browser.version < 7);	
		var b = jQuery(document.body);
		var w = jQuery(window);
		
		
		
		var msgbox = '<div class="'+ o.prefix +'box" id="'+ o.prefix +'box">';		
		if(o.useiframe && ((jQuery.browser.msie && jQuery('object, applet').length > 0) || ie6))//if you want to use the iframe uncomment these 3 lines
			msgbox += '<iframe src="javascript:;" class="'+ o.prefix +'fade" id="'+ o.prefix +'fade"></iframe>';
		else{ 
			if(ie6) jQuery('select').css('visibility','hidden');
			msgbox +='<div class="'+ o.prefix +'fade" id="'+ o.prefix +'fade"></div>';
		}	
		msgbox += '<div class="'+ o.prefix +'" id="'+ o.prefix +'"><div class="'+ o.prefix +'container"><div class="'+ o.prefix +'close">X</div><div class="'+ o.prefix +'message">'+ m +'</div><div class="'+ o.prefix +'buttons" id="'+ o.prefix +'buttons">';
		jQuery.each(o.buttons,function(k,v){ msgbox += '<button name="'+ o.prefix +'button'+ k +'" id="'+ o.prefix +'button'+ k +'" value="'+ v +'">'+ k +'</button>'}) ;
		msgbox += '</div></div></div></div>';
		
		var jqib =b.append(msgbox).children('#'+ o.prefix +'box');
		var jqi = jqib.children('#'+ o.prefix);
		var jqif = jqib.children('#'+ o.prefix +'fade');

		var getWindowScrollOffset = function(){ 
			return (document.documentElement.scrollTop || document.body.scrollTop) + 'px'; 
		};		
		
		var getWindowSize = function(){ 
			var size = {
				width: window.innerWidth || (window.document.documentElement.clientWidth || window.document.body.clientWidth),
				height: window.innerHeight || (window.document.documentElement.clientHeight || window.document.body.clientHeight)
			};
			return size;
		};
		
		var ie6scroll = function(){ 
			jqib.css({ top: getWindowScrollOffset() }); 
		};
		
		var fadeClicked = function(){
			if(o.persistent){
				var i = 0;
				jqib.addClass(o.prefix +'warning');
				var intervalid = setInterval(function(){ 
					jqib.toggleClass(o.prefix +'warning');
					if(i++ > 1){
						clearInterval(intervalid);
						jqib.removeClass(o.prefix +'warning');
					}
				}, 100);
			}
			else removePrompt();
		};		
		

		var escapeKeyClosePrompt = function(e){
			var key = (window.event) ? event.keyCode : e.keyCode; // MSIE or Firefox?
			if(key==27) removePrompt();
		};

		var positionPrompt = function(){
			var wsize = getWindowSize();
			jqib.css({ position: (ie6)? "absolute" : "fixed", height: wsize.height, width: "100%", top: (ie6)? getWindowScrollOffset():0, left: 0, right: 0, bottom: 0 });
			jqif.css({ position: "absolute", height: wsize.height, width: "100%", top: 0, left: 0, right: 0, bottom: 0 });
			jqi.css({ position: "absolute", top: o.top, left: "50%", marginLeft: ((((jqi.css("paddingLeft").split("px")[0]*1) + jqi.width())/2)*-1) });					
		};
		
		var stylePrompt = function(){
			jqif.css({ zIndex: o.zIndex, display: "none", opacity: o.opacity });
			jqi.css({ zIndex: o.zIndex+1, display: "none" });
			jqib.css({ zIndex: o.zIndex });
		}
		
		var removePrompt = function(callCallback, clicked, msg){
			jqi.remove(); 
			if(ie6)b.unbind('scroll',ie6scroll);//ie6, remove the scroll event
			w.unbind('resize',positionPrompt);			
			jqif.fadeOut(o.overlayspeed,function(){
				jqif.unbind('click',fadeClicked);
				jqif.remove();
				if(callCallback) o.callback(clicked,msg);
				jqib.unbind('keypress',escapeKeyClosePrompt);
				jqib.remove();
				if(ie6 && !o.useiframe) jQuery('select').css('visibility','visible');
			});
		}
		
		positionPrompt();
		stylePrompt();	

		//Events
		jQuery('#'+ o.prefix +'buttons').children('button').click(function(){ 
			var msg = jqi.children('.'+ o.prefix +'container').children('.'+ o.prefix +'message');
			var clicked = o.buttons[jQuery(this).text()];	
			if(o.submit(clicked,msg))				
				removePrompt(true,clicked,msg);
		});
		if(ie6) w.scroll(ie6scroll);//ie6, add a scroll event to fix position:fixed
		jqif.click(fadeClicked);
		w.resize(positionPrompt);
		jqib.keypress(escapeKeyClosePrompt);
		jqi.find('.'+ o.prefix +'close').click(removePrompt);
		
		//Show it
		jqif.fadeIn(o.overlayspeed);
		jqi[o.show](o.promptspeed,o.loaded);
		jqi.find('#'+ o.prefix +'buttons button:eq('+ o.focus +')').focus();//focus the default button
		return jqib;
	}	
});

 /****************************************************************
  *                                                              *
  *  JQuery Curvy Corners by Mike Jolley                         *
  *	 http://blue-anvil.com                                       *
  *  ------------                                                *
  *  Version 1.81                                                 *
  *                                                              *
  *  Origionaly by: Cameron Cooke and Tim Hutchison.             *
  *  Website: http://www.curvycorners.net                        *
  *                                                              *
  *  This library is free software; you can redistribute         *
  *  it and/or modify it under the terms of the GNU              *
  *  Lesser General Public License as published by the           *
  *  Free Software Foundation; either version 2.1 of the         *
  *  License, or (at your option) any later version.             *
  *                                                              *
  *  This library is distributed in the hope that it will        *
  *  be useful, but WITHOUT ANY WARRANTY; without even the       *
  *  implied warranty of MERCHANTABILITY or FITNESS FOR A        *
  *  PARTICULAR PURPOSE. See the GNU Lesser General Public       *
  *  License for more details.                                   *
  *                                                              *
  *  You should have received a copy of the GNU Lesser           *
  *  General Public License along with this library;             *
  *  Inc., 59 Temple Place, Suite 330, Boston,                   *
  *  MA 02111-1307 USA                                           *
  *                                                              *
  ****************************************************************/
(function($) {
$.fn.corner = function(options) {

	function BlendColour(Col1, Col2, Col1Fraction) {
		var red1 = parseInt(Col1.substr(1,2),16);
		var green1 = parseInt(Col1.substr(3,2),16);
		var blue1 = parseInt(Col1.substr(5,2),16);
		var red2 = parseInt(Col2.substr(1,2),16);
		var green2 = parseInt(Col2.substr(3,2),16);
		var blue2 = parseInt(Col2.substr(5,2),16);
		if(Col1Fraction > 1 || Col1Fraction < 0) Col1Fraction = 1;
		var endRed = Math.round((red1 * Col1Fraction) + (red2 * (1 - Col1Fraction)));
		if(endRed > 255) endRed = 255;
		if(endRed < 0) endRed = 0;
		var endGreen = Math.round((green1 * Col1Fraction) + (green2 * (1 - Col1Fraction)));
		if(endGreen > 255) endGreen = 255;
		if(endGreen < 0) endGreen = 0;
		var endBlue = Math.round((blue1 * Col1Fraction) + (blue2 * (1 - Col1Fraction)));
		if(endBlue > 255) endBlue = 255;
		if(endBlue < 0) endBlue = 0;
		return "#" + IntToHex(endRed)+ IntToHex(endGreen)+ IntToHex(endBlue);
	}
	
	function IntToHex(strNum) {
		base = strNum / 16;
		rem = strNum % 16;
		base = base - (rem / 16);
		baseS = MakeHex(base);
		remS = MakeHex(rem);
		return baseS + '' + remS;
	}
	
	function MakeHex(x) {
		if((x >= 0) && (x <= 9)) {
			return x; 
		} else {
			switch(x) {
				case 10: return "A";
				case 11: return "B";
				case 12: return "C";
				case 13: return "D";
				case 14: return "E";
				case 15: return "F";
			};
			return "F";
		};
	}
	
	function pixelFraction(x, y, r) {
		var pixelfraction = 0;
		var xvalues = new Array(1);
		var yvalues = new Array(1);
		var point = 0;
		var whatsides = "";
		var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x,2)));
		if ((intersect >= y) && (intersect < (y+1))) {
			whatsides = "Left";
			xvalues[point] = 0;
			yvalues[point] = intersect - y;
			point = point + 1;
		};
		var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y+1,2)));
		if ((intersect >= x) && (intersect < (x+1))) {
			whatsides = whatsides + "Top";
			xvalues[point] = intersect - x;
			yvalues[point] = 1;
			point = point + 1;
		};
		var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x+1,2)));
		if ((intersect >= y) && (intersect < (y+1))) {
			whatsides = whatsides + "Right";
			xvalues[point] = 1;
			yvalues[point] = intersect - y;
			point = point + 1;
		};
		var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y,2)));
		if ((intersect >= x) && (intersect < (x+1))) {
			whatsides = whatsides + "Bottom";
			xvalues[point] = intersect - x;
			yvalues[point] = 0;
		};
		switch (whatsides) {
			case "LeftRight":
			pixelfraction = Math.min(yvalues[0],yvalues[1]) + ((Math.max(yvalues[0],yvalues[1]) - Math.min(yvalues[0],yvalues[1]))/2);
			break;
			case "TopRight":
			pixelfraction = 1-(((1-xvalues[0])*(1-yvalues[1]))/2);
			break;
			case "TopBottom":
			pixelfraction = Math.min(xvalues[0],xvalues[1]) + ((Math.max(xvalues[0],xvalues[1]) - Math.min(xvalues[0],xvalues[1]))/2);
			break;
			case "LeftBottom":
			pixelfraction = (yvalues[0]*xvalues[1])/2;
			break;
			default:
			pixelfraction = 1;
		};
		return pixelfraction;
	}
	
	function rgb2Hex(rgbColour) {
		try {
			var rgbArray = rgb2Array(rgbColour);
			var red = parseInt(rgbArray[0]);
			var green = parseInt(rgbArray[1]);
			var blue = parseInt(rgbArray[2]);
			var hexColour = "#" + IntToHex(red) + IntToHex(green) + IntToHex(blue);
		} catch(e) {
			alert("There was an error converting the RGB value to Hexadecimal in function rgb2Hex");
		};
		return hexColour;
	}
	
	function rgb2Array(rgbColour) {
		var rgbValues = rgbColour.substring(4, rgbColour.indexOf(")"));
		var rgbArray = rgbValues.split(", ");
		return rgbArray;
	}
	
	function format_colour(colour) {
		var returnColour = "transparent";
		if(colour != "" && colour != "transparent")
		{
			if(colour.substr(0, 3) == "rgb")
			{
				returnColour = rgb2Hex(colour);
			}
			else if(colour.length == 4)
			{
				returnColour = "#" + colour.substring(1, 2) + colour.substring(1, 2) + colour.substring(2, 3) + colour.substring(2, 3) + colour.substring(3, 4) + colour.substring(3, 4);
			}
			else
			{
				returnColour = colour;
			};
		};
		return returnColour;
	};
	function strip_px(value) {
		return parseInt((( value != "auto" && value.indexOf("%") == -1 && value != "" && value.indexOf("px") !== -1)? value.slice(0, value.indexOf("px")) : 0))	
	}

    function drawPixel(box,intx, inty, colour, transAmount, height, newCorner, image, bgImage, cornerRadius, isBorder, borderWidth, boxWidth, settings) {
    	var $$ = $(box);
        var pixel = document.createElement("div");
        $(pixel).css({	height:height,width:"1px",position:"absolute","font-size":"1px",overflow:"hidden"	});
        //var topMaxRadius = Math.max(settings["tr"].radius, settings["tl"].radius);
        var topMaxRadius = Math.max(settings.tl ? settings.tl.radius : 0, settings.tr ? settings.tr.radius : 0);
        // Dont apply background image to border pixels
        if(image == -1 && bgImage != "") {
			if(topMaxRadius>0)
				$(pixel).css("background-position","-" + ((boxWidth - cornerRadius - borderWidth)+ intx) + "px -" + (($$.height() + topMaxRadius  - borderWidth )-inty) + "px");
			else 
				$(pixel).css("background-position","-" + ((boxWidth - cornerRadius - borderWidth)+ intx) + "px -" + (($$.height() )-inty) + "px");	
			$(pixel).css({
						 "background-image":bgImage,
						 "background-repeat":$$.css("background-repeat"),
						 "background-color":colour						 
			});
        }
        else
        {
			if (!isBorder) $(pixel).css("background-color",colour).addClass('hasBackgroundColor');
			else $(pixel).css("background-color",colour);
        };
        
        if (transAmount != 100)
        	setOpacity(pixel, transAmount);
        	//$(pixel).css('opacity',transAmount/100);
		$(pixel).css({top:inty + "px",left:intx + "px"});
        return pixel;
    };
    
	function setOpacity(obj, opacity) {
	  opacity = (opacity == 100)?99.999:opacity;
	
	  if($.browser.safari && obj.tagName != "IFRAME")
	  {
	      // Get array of RGB values
	      var rgbArray = rgb2Array(obj.style.backgroundColor);
	
	      // Get RGB values
	      var red   = parseInt(rgbArray[0]);
	      var green = parseInt(rgbArray[1]);
	      var blue  = parseInt(rgbArray[2]);
	
	      // Safari using RGBA support
	      obj.style.backgroundColor = "rgba(" + red + ", " + green + ", " + blue + ", " + opacity/100 + ")";
	  }
	  else if(typeof(obj.style.opacity) != "undefined")
	  {
	      // W3C
	      obj.style.opacity = opacity/100;
	  }
	  else if(typeof(obj.style.MozOpacity) != "undefined")
	  {
	      // Older Mozilla
	      obj.style.MozOpacity = opacity/100;
	  }
	  else if(typeof(obj.style.filter) != "undefined")
	  {
	      // IE
	      obj.style.filter = "alpha(opacity:" + opacity + ")";
	  }
	  else if(typeof(obj.style.KHTMLOpacity) != "undefined")
	  {
	      // Older KHTML Based Browsers
	      obj.style.KHTMLOpacity = opacity/100;
	  }
	}
		
	// Apply the corners
	function applyCorners(box,settings) {
	
		var $$ = $(box); 

		// Get CSS of box and define vars
		var thebgImage 			= $$.css("backgroundImage");
		var topContainer = null;
		var bottomContainer = null;
		var masterCorners = new Array();
		var contentDIV = null;
		var boxHeight 			= strip_px($$.css("height")) ? strip_px($$.css("height")) : box.scrollHeight; 
		var boxWidth 			= strip_px($$.css("width")) ? strip_px($$.css("width")) : box.scrollWidth; 
		var borderWidth     	= strip_px($$.css("borderTopWidth")) ? strip_px($$.css("borderTopWidth")) : 0; 
		var boxPaddingTop 		= strip_px($$.css("paddingTop"));
		var boxPaddingBottom 	= strip_px($$.css("paddingBottom"));
		var boxPaddingLeft 	= strip_px($$.css("paddingLeft"));
		
		var boxPaddingRight 	= strip_px($$.css("paddingRight"));
		var boxColour 			= format_colour($$.css("backgroundColor"));
		var bgImage 			= (thebgImage != "none" && thebgImage!="initial") ? thebgImage : "";
		//var boxContent 		= $$.html();
		var borderColour 		= format_colour($$.css("borderTopColor")); 
		var borderString 		= borderWidth + "px" + " solid " + borderColour;
		
		var topMaxRadius = Math.max(settings.tl ? settings.tl.radius : 0, settings.tr ? settings.tr.radius : 0);
		var botMaxRadius = Math.max(settings.bl ? settings.bl.radius : 0, settings.br ? settings.br.radius : 0);
		
		$$.addClass('hasCorners').css({"padding":"0", "borderColor":box.style.borderColour, 'overflow':'visible'});
		if(box.style.position != "absolute") $$.css("position","relative");
		if(($.browser.msie)) {
			if($.browser.version==6 && box.style.width == "auto" && box.style.height == "auto") $$.css("width","100%");
			$$.css("zoom","1");
			$($$ +" *").css("zoom","normal");
		}		
		
		for(var t = 0;t < 2;t++) {
			switch(t) {
				case 0:
				if(settings.tl || settings.tr) {
					var newMainContainer 	= document.createElement("div");
					topContainer		= box.appendChild(newMainContainer);
					$(topContainer).css({ width:"100%", "font-size":"1px", overflow:"hidden", position:"absolute", "padding-left":borderWidth, "padding-right":borderWidth, height:topMaxRadius + "px",top:0 - topMaxRadius + "px",left:0 - borderWidth + "px"}).addClass('topContainer');
				};
				break;
				case 1:
				if(settings.bl || settings.br) {
					var newMainContainer 	= document.createElement("div");
					bottomContainer	= box.appendChild(newMainContainer);
					$(bottomContainer).css({ width:"100%", "font-size":"1px", overflow:"hidden", position:"absolute", "padding-left":borderWidth, "padding-right":borderWidth, height:botMaxRadius,bottom:0 - botMaxRadius + "px",left:0 - borderWidth + "px"}).addClass('bottomContainer');
				};
				break;
			};
		};
		
		if(settings.autoPad == true) {
			//$$.html("");
			var contentContainer = document.createElement("div");
			var contentContainer2 = document.createElement("div");
			var clearDiv = document.createElement("div");
			
			$(contentContainer2).css({ margin:"0","padding-bottom":boxPaddingBottom,"padding-top":boxPaddingTop,"padding-left":boxPaddingLeft,"padding-right":boxPaddingRight, 'overflow':'visible'}).addClass('hasBackgroundColor content_container');

			$(contentContainer).css({position:"relative", 'float':"left",width:"100%", "margin-top":"-" + (topMaxRadius-borderWidth) + "px", "margin-bottom":"-" + (botMaxRadius-borderWidth) + "px"}).addClass = "autoPadDiv";
			
			$(clearDiv).css("clear","both");

			contentContainer2.appendChild(contentContainer);
			contentContainer2.appendChild(clearDiv);
			$$.wrapInner(contentContainer2);
		};
		
		if(topContainer) $$.css("border-top",0);
		if(bottomContainer) $$.css("border-bottom",0);
		var corners = ["tr", "tl", "br", "bl"];
		for(var i in corners) {
			if(i > -1 < 4) {
				var cc = corners[i];
				if(!settings[cc]) {

					if(((cc == "tr" || cc == "tl") && topContainer != null) || ((cc == "br" || cc == "bl") && bottomContainer != null)) {
						var newCorner = document.createElement("div");
						$(newCorner).css({position:"relative","font-size":"1px", overflow:"hidden"});
						
						if(bgImage == "")
							$(newCorner).css("background-color",boxColour);
						else
							$(newCorner).css("background-image",bgImage).css("background-color",boxColour);;

						switch(cc)
						{
							case "tl":							
								$(newCorner).css({height:topMaxRadius - borderWidth,"margin-right":settings.tr.radius - (borderWidth*2), "border-left":borderString,"border-top":borderString,left:-borderWidth + "px", "background-repeat":$$.css("background-repeat"), "background-position":borderWidth + "px 0px"});
							break;
							case "tr":
								$(newCorner).css({height:topMaxRadius - borderWidth,"margin-left":settings.tl.radius - (borderWidth*2), "border-right":borderString,"border-top":borderString,left:borderWidth + "px", "background-repeat":$$.css("background-repeat"), "background-position":"-" + (topMaxRadius + borderWidth) + "px 0px"});
							break;
							case "bl":
								if(topMaxRadius>0)
									$(newCorner).css({height:botMaxRadius - borderWidth,"margin-right":settings.br.radius - (borderWidth*2), "border-left":borderString,"border-bottom":borderString,left:-borderWidth + "px", "background-repeat":$$.css("background-repeat"), "background-position":"0px -" + ($$.height() + topMaxRadius  - borderWidth +1) + "px" });
								else
									$(newCorner).css({height:botMaxRadius - borderWidth,"margin-right":settings.br.radius - (borderWidth*2), "border-left":borderString,"border-bottom":borderString,left:-borderWidth + "px", "background-repeat":$$.css("background-repeat"), "background-position":"0px -" + ($$.height()) + "px" });
							break;
							case "br":
								if(topMaxRadius>0)
									$(newCorner).css({height:botMaxRadius - borderWidth,"margin-left":settings.bl.radius - (borderWidth*2), "border-right":borderString,"border-bottom":borderString,left:borderWidth + "px", "background-repeat":$$.css("background-repeat"),  "background-position":"-" + settings.bl.radius + borderWidth + "px -" + ($$.height() + topMaxRadius  - borderWidth + 1) + "px" });
								else
									$(newCorner).css({height:botMaxRadius - borderWidth,"margin-left":settings.bl.radius - (borderWidth*2), "border-right":borderString,"border-bottom":borderString,left:borderWidth + "px", "background-repeat":$$.css("background-repeat"),  "background-position":"-" + settings.bl.radius + borderWidth + "px -" + ($$.height()) + "px" });
							break;
						};
					};
				} else {
					if(masterCorners[settings[cc].radius]) {
						var newCorner = masterCorners[settings[cc].radius].cloneNode(true);
					} else {
						var newCorner = document.createElement("DIV");
						$(newCorner).css({	height:settings[cc].radius,width:settings[cc].radius,position:"absolute","font-size":"1px",overflow:"hidden"	});
						var borderRadius = parseInt(settings[cc].radius - borderWidth);
						for(var intx = 0, j = settings[cc].radius; intx < j; intx++) {
							if((intx +1) >= borderRadius)
								var y1 = -1;
							else
								var y1 = (Math.floor(Math.sqrt(Math.pow(borderRadius, 2) - Math.pow((intx+1), 2))) - 1);
							if(borderRadius != j) {
								if((intx) >= borderRadius)
								var y2 = -1;
								else
								var y2 = Math.ceil(Math.sqrt(Math.pow(borderRadius,2) - Math.pow(intx, 2)));
								if((intx+1) >= j)
								var y3 = -1;
								else
								var y3 = (Math.floor(Math.sqrt(Math.pow(j ,2) - Math.pow((intx+1), 2))) - 1);
							};
							if((intx) >= j)
								var y4 = -1;
							else
								var y4 = Math.ceil(Math.sqrt(Math.pow(j ,2) - Math.pow(intx, 2)));
							if(y1 > -1) newCorner.appendChild(drawPixel(box,intx, 0, boxColour, 100, (y1+1), newCorner, -1, bgImage, settings[cc].radius, 0, borderWidth, boxWidth, settings));
							if(borderRadius != j) {
								for(var inty = (y1 + 1); inty < y2; inty++) {
									if(settings.antiAlias) {
										if(bgImage != "") {
											var borderFract = (pixelFraction(intx, inty, borderRadius) * 100);
											if(borderFract < 30) {
												newCorner.appendChild(drawPixel(box,intx, inty, borderColour, 100, 1, newCorner, 0, bgImage, settings[cc].radius, 1, borderWidth, boxWidth, settings));
											} else {
												newCorner.appendChild(drawPixel(box,intx, inty, borderColour, 100, 1, newCorner, -1, bgImage, settings[cc].radius, 1, borderWidth, boxWidth, settings));
											};
										} else {
											var pixelcolour = BlendColour(boxColour, borderColour, pixelFraction(intx, inty, borderRadius));
											newCorner.appendChild(drawPixel(box,intx, inty, pixelcolour, 100, 1, newCorner, 0, bgImage, settings[cc].radius, cc, 1, borderWidth, boxWidth, settings));
										};
									};
								};
								if(settings.antiAlias) {
									  if(y3 >= y2)
									  {
										 if (y2 == -1) y2 = 0;
										 newCorner.appendChild(drawPixel(box,intx, y2, borderColour, 100, (y3 - y2 + 1), newCorner, 0,bgImage, 0, 1, borderWidth, boxWidth, settings));
									  }
								} else {
									  if(y3 >= y1)
									  {
										  newCorner.appendChild(drawPixel(box,intx, (y1 + 1), borderColour, 100, (y3 - y1), newCorner, 0,bgImage, 0, 1, borderWidth, boxWidth, settings));
									  }
								};
								var outsideColour = borderColour;
							} else {
								var outsideColour = boxColour;
								var y3 = y1;
							};
							if(settings.antiAlias) {
								for(var inty = (y3 + 1); inty < y4; inty++) {
									newCorner.appendChild(drawPixel(box,intx, inty, outsideColour, (pixelFraction(intx, inty , j) * 100), 1, newCorner, ((borderWidth > 0)? 0 : -1),bgImage, settings[cc].radius, 1, borderWidth, boxWidth, settings));
								};                                
							};
						};
						masterCorners[settings[cc].radius] = newCorner.cloneNode(true);                                           
					};                    
					if(cc != "br") {
						for(var t = 0, k = newCorner.childNodes.length; t < k; t++) {
							var pixelBar 			= newCorner.childNodes[t];
							var pixelBarTop 		= strip_px($(pixelBar).css("top"));
							var pixelBarLeft 		= strip_px($(pixelBar).css("left"));
							var pixelBarHeight 		= strip_px($(pixelBar).css("height"));
							
							if(cc == "tl" || cc == "bl") {
								$(pixelBar).css("left",settings[cc].radius -pixelBarLeft -1 + "px");
							};
							
							if(cc == "tr" || cc == "tl") {
								$(pixelBar).css("top", settings[cc].radius -pixelBarHeight -pixelBarTop + "px");
							};
							
							switch(cc) {
								case "tr":
									$(pixelBar).css("background-position","-" + Math.abs((boxWidth - settings[cc].radius + borderWidth) + pixelBarLeft) + "px -" + Math.abs(settings[cc].radius -pixelBarHeight -pixelBarTop - borderWidth) + "px");
								break;
								case "tl":
									$(pixelBar).css("background-position","-" + Math.abs((settings[cc].radius -pixelBarLeft -1) - borderWidth) + "px -" + Math.abs(settings[cc].radius -pixelBarHeight -pixelBarTop - borderWidth) + "px");
								break;
								case "bl":
									if(topMaxRadius>0)
										$(pixelBar).css("background-position", "-" + Math.abs((settings[cc].radius -pixelBarLeft -1) - borderWidth) + "px -" + Math.abs(($$.height() + topMaxRadius - borderWidth + 1)) + "px");
									else
										$(pixelBar).css("background-position", "-" + Math.abs((settings[cc].radius -pixelBarLeft -1) - borderWidth) + "px -" + Math.abs(($$.height())) + "px");
								break;
							};
						};
					};
				};
				
				if(newCorner) {
					switch(cc) {
						case "tl":
						if($(newCorner).css("position") == "absolute") $(newCorner).css("top","0");
						if($(newCorner).css("position") == "absolute") $(newCorner).css("left","0");
						if(topContainer) topContainer.appendChild(newCorner);
						break;
						case "tr":
						if($(newCorner).css("position") == "absolute") $(newCorner).css("top","0");
						if($(newCorner).css("position") == "absolute") $(newCorner).css("right","0");
						if(topContainer) topContainer.appendChild(newCorner);
						break;
						case "bl":
						if($(newCorner).css("position") == "absolute") $(newCorner).css("bottom","0");
						if(newCorner.style.position == "absolute") $(newCorner).css("left","0");
						if(bottomContainer) bottomContainer.appendChild(newCorner);
						break;
						case "br":
						if($(newCorner).css("position") == "absolute") $(newCorner).css("bottom","0");
						if($(newCorner).css("position") == "absolute") $(newCorner).css("right","0");
						if(bottomContainer) bottomContainer.appendChild(newCorner);
						break;
					};                    
				};
			};
		};
		
		var radiusDiff = new Array();
		radiusDiff["t"] = Math.abs(settings.tl.radius - settings.tr.radius);
		radiusDiff["b"] = Math.abs(settings.bl.radius - settings.br.radius);
		for(z in radiusDiff) {
			if(z == "t" || z == "b") {
				if(radiusDiff[z]) {
					var smallerCornerType = ((settings[z + "l"].radius < settings[z + "r"].radius)? z +"l" : z +"r");
					var newFiller = document.createElement("div");
					$(newFiller).css({	height:radiusDiff[z],width:settings[smallerCornerType].radius+ "px",position:"absolute","font-size":"1px",overflow:"hidden","background-color":boxColour,"background-image":bgImage	});
				  switch(smallerCornerType)
				  {
					  case "tl":
						$(newFiller).css({"bottom":"0","left":"0","border-left":borderString,"background-position":"0px -" + (settings[smallerCornerType].radius - borderWidth )});
						topContainer.appendChild(newFiller);
						break;
	
					  case "tr":
						$(newFiller).css({"bottom":"0","right":"0","border-right":borderString,"background-position":"0px -" + (settings[smallerCornerType].radius - borderWidth ) + "px"});
						topContainer.appendChild(newFiller);
						break;
	
					  case "bl":
						$(newFiller).css({"top":"0","left":"0","border-left":borderString,"background-position":"0px -" + ($$.height() + settings[smallerCornerType].radius - borderWidth )});
						bottomContainer.appendChild(newFiller);
						break;
	
					  case "br":
						$(newFiller).css({"top":"0","right":"0","border-right":borderString,"background-position":"0px -" + ($$.height() + settings[smallerCornerType].radius - borderWidth )});
						bottomContainer.appendChild(newFiller);
						
						break;
				  }
			};
				
			var newFillerBar = document.createElement("div");
			$(newFillerBar).css({	position:"relative","font-size":"1px",overflow:"hidden","background-color":boxColour,"background-image":bgImage,"background-repeat":$$.css("background-repeat")});
			switch(z) {
					case "t":
					if(topContainer) {
						if(settings.tl.radius && settings.tr.radius) {
							$(newFillerBar).css({
												height:topMaxRadius - borderWidth + "px",
												"margin-left":settings.tl.radius - borderWidth  + "px",
												"margin-right":settings.tr.radius - borderWidth  + "px",
												"border-top":borderString
							}).addClass('hasBackgroundColor');
						
							if(bgImage != "")
								$(newFillerBar).css("background-position","-" + (topMaxRadius + borderWidth) + "px 0px");
							
							topContainer.appendChild(newFillerBar);
							
						}; 
						$$.css("background-position", "0px -" + (topMaxRadius - borderWidth +1) + "px"); 
					}; 
					break;
					case "b":
					if(bottomContainer) {
						if(settings.bl.radius && settings.br.radius) {
							$(newFillerBar).css({	
												height:botMaxRadius - borderWidth + "px",
												"margin-left":settings.bl.radius - borderWidth + "px",
												"margin-right":settings.br.radius - borderWidth + "px",
												"border-bottom":borderString
							});
						
							if(bgImage != "" && topMaxRadius>0)
								$(newFillerBar).css("background-position","-" + (settings.bl.radius - borderWidth) + "px -" + ($$.height() + topMaxRadius - borderWidth + 1) + "px");
							else
								$(newFillerBar).css("background-position","-" + (settings.bl.radius - borderWidth) + "px -" + ($$.height() ) + "px").addClass('hasBackgroundColor');
							
							bottomContainer.appendChild(newFillerBar);
						};
					};
					break;
				};
			};
		};
		$$.prepend(topContainer);
		$$.prepend(bottomContainer);
	}

	var settings = {
	  tl: { radius: 8 },
	  tr: { radius: 8 },
	  bl: { radius: 8 },
	  br: { radius: 8 },
	  antiAlias: true,
	  autoPad: true,
	  validTags: ["div"] };
	if ( options && typeof(options) != 'string' )
		$.extend(settings, options);
            
	return this.each(function() {
		if (!$(this).is('.hasCorners')) {
			applyCorners(this, settings);				
		}
		
	}); 
			
};
})(jQuery);
/*
 * One Click Upload - jQuery Plugin
 * Copyright (c) 2008 Michael Mitchell - http://www.michaelmitchell.co.nz
 */
(function($){
	$.fn.upload = function(options) {
		/** Merge the users options with our defaults */
		options = $.extend({
			name: 'file',
			enctype: 'multipart/form-data',
			action: '',
			autoSubmit: true,
			onSubmit: function() {},
			onComplete: function() {},
			onSelect: function() {},
			params: {}
		}, options);
		return new $.ocupload(this, options);
	},
	
	$.ocupload = function(element, options) {
		/** Fix scope problems */
		var self = this;
	
		/** A unique id so we can find our elements later */
		var id = new Date().getTime().toString().substr(8);
		
		/** Upload Iframe */
		var iframe = $(
			'<iframe '+
				'id="iframe'+id+'" '+
				'name="iframe'+id+'"'+
			'></iframe>'
		).css({
			display: 'none'
		});
		
		/** Form */
		var form = $(
			'<form '+
				'method="post" '+
				'enctype="'+options.enctype+'" '+
				'action="'+options.action+'" '+
				'target="iframe'+id+'"'+
			'></form>'
		).css({
			margin: 0,
			padding: 0
		});
		
		/** File Input */
		var input = $(
			'<input '+
				'name="'+options.name+'" '+
				'type="file" '+
			'/>'
		).css({
			position: 'relative',
			display: 'block',
			marginLeft: -175+'px',
			opacity: 0
		});
		
		/** Put everything together */
		element.wrap('<div></div>'); //container
			form.append(input);
			element.after(form);
			element.after(iframe);
	
		/** Find the container and make it nice and snug */
		var container = element.parent().css({
			position: 'relative',
			height: element.outerHeight()+'px',
			width: element.outerWidth()+'px',
			overflow: 'hidden',
			cursor: 'pointer',
			margin: 0,
			padding: 0
		});
			
		/** Put our file input in the right place */
		input.css('marginTop', -container.height()-10+'px');

		/** Move the input with the mouse to make sure it get clicked! */
		container.mousemove(function(e){
			input.css({
				top: e.pageY-container.offset().top+'px',
				left: e.pageX-container.offset().left+'px'
			});
		});
		
		/** Watch for file selection */
		input.change(function() {
			/** Do something when a file is selected. */
			self.onSelect(); 
			
			/** Submit the form automaticly after selecting the file */
			if(self.autoSubmit) {
				self.submit();
			}
		});
		
		/** Methods */
		$.extend(this, {
			autoSubmit: true,
			onSubmit: options.onSubmit,
			onComplete: options.onComplete,
			onSelect: options.onSelect,
		
			/** get filename */		
			filename: function() {
				return input.attr('value');
			},
			
			/** get/set params */
			params: function(params) {
				var params = params ? params : false;
				
				if(params) {
					options.params = $.extend(options.params, params);
				}
				else {
					return options.params;
				}
			},
			
			/** get/set name */
			name: function(name) {
				var name = name ? name : false;
				
				if(name) {
					input.attr('name', value);
				}
				else {
					return input.attr('name');
				}
			},
			
			/** get/set action */
			action: function(action) {
				var action = action ? action : false;
				
				if(action) {
					form.attr('action', action);
				}
				else {
					return form.attr('action');
				}
			},
			
			/** get/set enctype */
			enctype: function(enctype) {
				var enctype = enctype ? enctype : false;
				
				if(enctype) {
					form.attr('enctype', enctype);
				}
				else {
					return form.attr('enctype');
				}
			},
			
			/** set options */
			set: function(obj, value) {
				var value =	value ? value : false;
								
				function option(action, value) {
					switch(action) {
						default:
							throw new Error('[jQuery.ocupload.set] \''+action+'\' is an invalid option.');
							break;
						case 'name':
							self.name(value);
							break;
						case 'action':
							self.action(value);
							break;
						case 'enctype':
							self.enctype(value);
							break;
						case 'params':
							self.params(value);
							break;
						case 'autoSubmit':
							self.autoSubmit = value;
							break;
						case 'onSubmit':
							self.onSubmit = value;
							break;
						case 'onComplete':
							self.onComplete = value;
							break;
						case 'onSelect':
							self.onSelect = value;
							break;
					}
				}				
				
				if(value) {
					option(obj, value);
				}
				else {				
					$.each(obj, function(key, value) {
						option(key, value);
					});
				}
			},
			
			/** Submit the form */
			submit: function() {
				/** Do something before we upload */
				this.onSubmit();
				
				/** add additional paramters before sending */
				$.each(options.params, function(key, value) {
					form.append($(
						'<input '+
							'type="hidden" '+
							'name="'+key+'" '+
							'value="'+value+'" '+
						'/>'
					));
				});
				/** Submit the actual form */
				form.submit(); 
				
				/** Do something after we are finished uploading */
				iframe.unbind().load(function() {
					/** Get a response from the server in plain text */
					var myFrame = document.getElementById(iframe.attr('name'));
					var response = $(myFrame.contentWindow.document.body);
					
					/** Do something on complete */
					self.onComplete(response); //done :D
				});
			}
		});
	}
})(jQuery);
/**
 * dxCombobox 1.2 (2008-04-22)
 *
 * Copyright (c) 2008 Dipesh Nyachhyon (http://dmashups.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * Built upon jQuery 1.2.3 (http://jquery.com)
 * 
 * dxCombobox plugin allows you to transform any < select > element into an editable combobox.
 * Pressing any alphanumeric key will transform select box into editable state by creating a
 * text box element. An case insensitive search is performed on the corresponding < option > of the select
 * box, one the users starts to type in this box. When user goes out of the box (on blur/return),
 * if a direct match is found in the < option > then it is selected else a new option is created
 * with the entered text.
 * - CSS class applied to the selectbox is applied to the created textbox as well
 * 
 * Syntax:
 * $(element).dxCombobox([options])
 * 
 * Parameters:
 * - plugin specific options
 * 
 * Options:
 * - int maxlength: maximum length to allow in editable text box, default is 35 characters
 * 
 * Change log
 * - 1.2
 * 		- fix for, if i type 'Dexter' and press enter then a new option is created and selected; now again if i type 'Dexter' and press enter, then the text(option) is lost
 * 		- fix for, initial key pressed not appearing in the textbox for IE6
 */
(function($) {
	$.fn.dxCombobox	=	function(options) {
		var defaults	=	{
			maxlength: 35
		}		
		var xClass		=	'dxComboboxClass';
		
		// options
		var options = $.extend(defaults, options);		
		
		// select box attributes
		var strSelId	=	$(this).attr('id');
		var strBoxId	=	'txt_' + strSelId;
		var objSel		=	$(this);
		
		// bind key press event
		return $(this).bind('keydown', function(e) {
			var intKey	=	$.dxCombobox.event(e);
			switch (intKey) {
				case 8: // backspace
				case 9: // tab
				case 13: // return
				case 16: // shift
				case 17: // ctrl
				case 18: // alt
				case 27: // escape
				case 33: // page up
				case 34: // page down
				case 35: // end
				case 36: // home
				case 37: // left
				case 38: // up
				case 39: // right
				case 40: // down
				case 45: // insert
				case 46: // delete
					break;
				default:
					// remove selection from all options
					objSel.children(':selected').removeAttr('selected');
					
					// hide select box
					objSel.hide();
					
					// create text box if not created already
					if (document.getElementById(strBoxId) == null) {
						var objBox	=	document.createElement('input');
						$(objBox).width(objSel.width()).attr('type', 'text').attr('id', strBoxId).attr('autocomplete', 'off').attr('maxlength', defaults.maxlength).addClass(objSel.attr('class'));
						
						// display text box
						objSel.after(objBox);
						
						// set focus
						objBox.focus();
						
						// for IE 6, capture key event, convert to character and put it in text box
						if ($.browser.msie) {
							if ($.dxCombobox.ieVersion() < 7) {
								var range = document.selection.createRange();
								range.moveStart('character', 1); //move cursor at the end of line ... i.e. after this entered character
								$(objBox).val(String.fromCharCode(intKey)); // insert capture key into the text box
							}
						}
						
						// bind event to this text box							
						$(objBox).bind('keydown', function(elt) {
							var txtKey	=	$.dxCombobox.event(elt);
							// trigger blur event and return focus back to select box when 'return' key is pressed
							if (txtKey == 13) {
								$(objBox).trigger('blur');
								objSel.focus().focus().next().focus(); //envoke extra focus event to make it compatible with IE
							}
							// clear text, trigger blur and return focus back to select box whe "escape" key is pressed
							if (txtKey == 27) {
								$(objBox).val('').trigger('blur');
								objSel.focus().focus().next().focus(); //envoke extra focus event to make it compatible with IE
							}
						});	
					}
					
					// autocomplete (with highlighting)
					$.dxCombobox.autoFill(strBoxId, objSel);
				break;
			}
			
			// bind on blur event
			$('#' + strBoxId).bind('blur', function() {
				//create new option?
				var bolCreateOption	=	true;
				
				// search option with same value as in text box
				objSel.children().each(function() {
					if (!$(this).hasClass(xClass)) { //don't search in the created option
						if ($(this).text().toLowerCase() == $('#' + strBoxId).val().toLowerCase()) {
							$(this).attr('selected', 'selected');
							bolCreateOption = false;
						}
					}
				});
				
				// create new option in select box (if it has not been created before) and if needed
				if (!objSel.children().hasClass(xClass) && bolCreateOption) {
					objSel.prepend("<option class=\""+xClass+"\" selected></option>");
				}
				
				// if no option found with text that matches the value in text box
				if (bolCreateOption) {
					// if it has some text then update option else remove this created option
					if ($(this).val() != '') {
						// update key/value in option
						objSel.children('option.' + xClass).text($(this).val()).val($(this).val()).attr('selected', 'selected');
					}
					else {
						// if no value entered in text box, remove this option
						objSel.children('option.' + xClass).remove();
					}
				} else {
					// if a match found, then remove this option
					objSel.children('option.' + xClass).remove();
				}
				
				// display select box
				objSel.show();
				
				// destroy text box
				var objNode	=	document.getElementById(strBoxId);
				objNode.parentNode.removeChild(objNode);
			});
		});
	}
})(jQuery);

/**
 * helper plugins for combobox
 */
(function($) {
	$.dxCombobox	=	{
		event: function(e) {
			var intKey = 0;				
			if (!e) var e = window.event;
			if (e.keyCode) intKey = e.keyCode; else { if (e.which) intKey = e.which; }
			return intKey;
		},
		autoFill: function(strBoxId, objSel) {
			var objTextBox	=	$('#' + strBoxId);
			objTextBox.bind('keyup', function(e) {
				var strKeyword	=	objTextBox.val().toLowerCase();
				var intKey		=	$.dxCombobox.event(e);
				switch (intKey) {
					case 8: // BACKSPACE
					case 9: // TAB (?)
					case 33: // PAGE UP
					case 34: // PAGE DOWN
					case 35: // END
					case 36: // HOME
					case 37: // CURSOR LEFT
					case 38: // CURSOR UP
					case 39: // CURSOR RIGHT
					case 40: // CURSOR DOWN
					case 45: // INSERT
					case 46: // DELETE
					case 27: // ESCAPE
					case 13: // RETURN
						break;
					default:
						// search for a match in the option text
						objSel.children().each(function() {
							var strOption	=	$(this).text();
							var intPos		=	strOption.toLowerCase().indexOf(strKeyword);
							
							if (intPos == 0) {
								var intStart	=	strKeyword.length;
								var intEnd		=	strOption.length;
								
								objTextBox.val(strOption);
								
								// for IE
								if ($.browser.msie) {
									var range = document.getElementById(strBoxId).createTextRange();
									range.moveStart('character', intStart);
									range.select();
								} else {
									// for others
									if (intStart == 0) intStart	=	intStart + 1;
									document.getElementById(strBoxId).setSelectionRange(intStart, intEnd);
								}								
								return false; //exit from loop
							}
						});
					break;
				}
			});
		},
		ieVersion: function() {			
			var objUa		=	navigator.userAgent;
			var intIEOffset	=	objUa.indexOf("MSIE ");			    
			if (intIEOffset == -1) return 0;
			else return parseFloat(objUa.substring(intIEOffset + 5, objUa.indexOf(";", intIEOffset)));
		}
	}
})(jQuery);
/**
 * jQuery.ScrollTo
 * Copyright (c) 2007-2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
 * Dual licensed under MIT and GPL.
 * Date: 9/11/2008
 *
 * @projectDescription Easy element scrolling using jQuery.
 * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
 * Tested with jQuery 1.2.6. On FF 2/3, IE 6/7, Opera 9.2/5 and Safari 3. on Windows.
 *
 * @author Ariel Flesler
 * @version 1.4
 *
 * @id jQuery.scrollTo
 * @id jQuery.fn.scrollTo
 * @param {String, Number, DOMElement, jQuery, Object} target Where to scroll the matched elements.
 *	  The different options for target are:
 *		- A number position (will be applied to all axes).
 *		- A string position ('44', '100px', '+=90', etc ) will be applied to all axes
 *		- A jQuery/DOM element ( logically, child of the element to scroll )
 *		- A string selector, that will be relative to the element to scroll ( 'li:eq(2)', etc )
 *		- A hash { top:x, left:y }, x and y can be any kind of number/string like above.
 * @param {Number} duration The OVERALL length of the animation, this argument can be the settings object instead.
 * @param {Object,Function} settings Optional set of settings or the onAfter callback.
 *	 @option {String} axis Which axis must be scrolled, use 'x', 'y', 'xy' or 'yx'.
 *	 @option {Number} duration The OVERALL length of the animation.
 *	 @option {String} easing The easing method for the animation.
 *	 @option {Boolean} margin If true, the margin of the target element will be deducted from the final position.
 *	 @option {Object, Number} offset Add/deduct from the end position. One number for both axes or { top:x, left:y }.
 *	 @option {Object, Number} over Add/deduct the height/width multiplied by 'over', can be { top:x, left:y } when using both axes.
 *	 @option {Boolean} queue If true, and both axis are given, the 2nd axis will only be animated after the first one ends.
 *	 @option {Function} onAfter Function to be called after the scrolling ends. 
 *	 @option {Function} onAfterFirst If queuing is activated, this function will be called after the first scrolling ends.
 * @return {jQuery} Returns the same jQuery object, for chaining.
 *
 * @desc Scroll to a fixed position
 * @example $('div').scrollTo( 340 );
 *
 * @desc Scroll relatively to the actual position
 * @example $('div').scrollTo( '+=340px', { axis:'y' } );
 *
 * @dec Scroll using a selector (relative to the scrolled element)
 * @example $('div').scrollTo( 'p.paragraph:eq(2)', 500, { easing:'swing', queue:true, axis:'xy' } );
 *
 * @ Scroll to a DOM element (same for jQuery object)
 * @example var second_child = document.getElementById('container').firstChild.nextSibling;
 *			$('#container').scrollTo( second_child, { duration:500, axis:'x', onAfter:function(){
 *				alert('scrolled!!');																   
 *			}});
 *
 * @desc Scroll on both axes, to different values
 * @example $('div').scrollTo( { top: 300, left:'+=200' }, { axis:'xy', offset:-20 } );
 */
;(function( $ ){
	
	var $scrollTo = $.scrollTo = function( target, duration, settings ){
		$(window).scrollTo( target, duration, settings );
	};

	$scrollTo.defaults = {
		axis:'y',
		duration:1
	};

	// Returns the element that needs to be animated to scroll the window.
	// Kept for backwards compatibility (specially for localScroll & serialScroll)
	$scrollTo.window = function( scope ){
		return $(window).scrollable();
	};

	// Hack, hack, hack... stay away!
	// Returns the real elements to scroll (supports window/iframes, documents and regular nodes)
	$.fn.scrollable = function(){
		return this.map(function(){
			// Just store it, we might need it
			var win = this.parentWindow || this.defaultView,
				// If it's a document, get its iframe or the window if it's THE document
				elem = this.nodeName == '#document' ? win.frameElement || win : this,
				// Get the corresponding document
				doc = elem.contentDocument || (elem.contentWindow || elem).document,
				isWin = elem.setInterval;

			return elem.nodeName == 'IFRAME' || isWin && $.browser.safari ? doc.body
				: isWin ? doc.documentElement
				: this;
		});
	};

	$.fn.scrollTo = function( target, duration, settings ){
		if( typeof duration == 'object' ){
			settings = duration;
			duration = 0;
		}
		if( typeof settings == 'function' )
			settings = { onAfter:settings };
			
		settings = $.extend( {}, $scrollTo.defaults, settings );
		// Speed is still recognized for backwards compatibility
		duration = duration || settings.speed || settings.duration;
		// Make sure the settings are given right
		settings.queue = settings.queue && settings.axis.length > 1;
		
		if( settings.queue )
			// Let's keep the overall duration
			duration /= 2;
		settings.offset = both( settings.offset );
		settings.over = both( settings.over );

		return this.scrollable().each(function(){
			var elem = this,
				$elem = $(elem),
				targ = target, toff, attr = {},
				win = $elem.is('html,body');

			switch( typeof targ ){
				// A number will pass the regex
				case 'number':
				case 'string':
					if( /^([+-]=)?\d+(px)?$/.test(targ) ){
						targ = both( targ );
						// We are done
						break;
					}
					// Relative selector, no break!
					targ = $(targ,this);
				case 'object':
					// DOMElement / jQuery
					if( targ.is || targ.style )
						// Get the real position of the target 
						toff = (targ = $(targ)).offset();
			}
			$.each( settings.axis.split(''), function( i, axis ){
				var Pos	= axis == 'x' ? 'Left' : 'Top',
					pos = Pos.toLowerCase(),
					key = 'scroll' + Pos,
					old = elem[key],
					Dim = axis == 'x' ? 'Width' : 'Height',
					dim = Dim.toLowerCase();

				if( toff ){// jQuery / DOMElement
					attr[key] = toff[pos] + ( win ? 0 : old - $elem.offset()[pos] );

					// If it's a dom element, reduce the margin
					if( settings.margin ){
						attr[key] -= parseInt(targ.css('margin'+Pos)) || 0;
						attr[key] -= parseInt(targ.css('border'+Pos+'Width')) || 0;
					}
					
					attr[key] += settings.offset[pos] || 0;
					
					if( settings.over[pos] )
						// Scroll to a fraction of its width/height
						attr[key] += targ[dim]() * settings.over[pos];
				}else
					attr[key] = targ[pos];

				// Number or 'number'
				if( /^\d+$/.test(attr[key]) )
					// Check the limits
					attr[key] = attr[key] <= 0 ? 0 : Math.min( attr[key], max(Dim) );

				// Queueing axes
				if( !i && settings.queue ){
					// Don't waste time animating, if there's no need.
					if( old != attr[key] )
						// Intermediate animation
						animate( settings.onAfterFirst );
					// Don't animate this axis again in the next iteration.
					delete attr[key];
				}
			});			
			animate( settings.onAfter );			

			function animate( callback ){
				$elem.animate( attr, duration, settings.easing, callback && function(){
					callback.call(this, target, settings);
				});
			};
			function max( Dim ){
				var attr ='scroll'+Dim,
					doc = elem.ownerDocument;
				
				return win
						? Math.max( doc.documentElement[attr], doc.body[attr]  )
						: elem[attr];
			};
		}).end();
	};

	function both( val ){
		return typeof val == 'object' ? val : { top:val, left:val };
	};

})( jQuery );
/*
 * jQuery JSON Plugin
 * version: 1.0 (2008-04-17)
 *
 * This document is licensed as free software under the terms of the
 * MIT License: http://www.opensource.org/licenses/mit-license.php
 *
 * Brantley Harris technically wrote this plugin, but it is based somewhat
 * on the JSON.org website's http://www.json.org/json2.js, which proclaims:
 * "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that
 * I uphold.  I really just cleaned it up.
 *
 * It is also based heavily on MochiKit's serializeJSON, which is 
 * copywrited 2005 by Bob Ippolito.
 */
 
(function($) {   
    function toIntegersAtLease(n) 
    // Format integers to have at least two digits.
    {    
        return n < 10 ? '0' + n : n;
    }

    Date.prototype.toJSON = function(date)
    // Yes, it polutes the Date namespace, but we'll allow it here, as
    // it's damned usefull.
    {
        return this.getUTCFullYear()   + '-' +
             toIntegersAtLease(this.getUTCMonth()) + '-' +
             toIntegersAtLease(this.getUTCDate());
    };

    var escapeable = /["\\\x00-\x1f\x7f-\x9f]/g;
    var meta = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        };
        
    $.quoteString = function(string)
    // Places quotes around a string, inteligently.
    // If the string contains no control characters, no quote characters, and no
    // backslash characters, then we can safely slap some quotes around it.
    // Otherwise we must also replace the offending characters with safe escape
    // sequences.
    {
        if (escapeable.test(string))
        {
            return '"' + string.replace(escapeable, function (a) 
            {
                var c = meta[a];
                if (typeof c === 'string') {
                    return c;
                }
                c = a.charCodeAt();
                return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
            }) + '"';
        }
        return '"' + string + '"';
    };
    
    $.toJSON = function(o, compact)
    {
        var type = typeof(o);
        
        if (type == "undefined")
            return "undefined";
        else if (type == "number" || type == "boolean")
            return o + "";
        else if (o === null)
            return "null";
        
        // Is it a string?
        if (type == "string") 
        {
            return $.quoteString(o);
        }
        
        // Does it have a .toJSON function?
        if (type == "object" && typeof o.toJSON == "function") 
            return o.toJSON(compact);
        
        // Is it an array?
        if (type != "function" && typeof(o.length) == "number") 
        {
            var ret = [];
            for (var i = 0; i < o.length; i++) {
                ret.push( $.toJSON(o[i], compact) );
            }
            if (compact)
                return "[" + ret.join(",") + "]";
            else
                return "[" + ret.join(", ") + "]";
        }
        
        // If it's a function, we have to warn somebody!
        if (type == "function") {
            throw new TypeError("Unable to convert object of type 'function' to json.");
        }
        
        // It's probably an object, then.
        var ret = [];
        for (var k in o) {
            var name;
            type = typeof(k);
            
            if (type == "number")
                name = '"' + k + '"';
            else if (type == "string")
                name = $.quoteString(k);
            else
                continue;  //skip non-string or number keys
            
            var val = $.toJSON(o[k], compact);
            if (typeof(val) != "string") {
                // skip non-serializable values
                continue;
            }
            
            if (compact)
                ret.push(name + ":" + val);
            else
                ret.push(name + ": " + val);
        }
        return "{" + ret.join(", ") + "}";
    };
    
    $.compactJSON = function(o)
    {
        return $.toJSON(o, true);
    };
    
    $.evalJSON = function(src)
    // Evals JSON that we know to be safe.
    {
        return eval("(" + src + ")");
    };
    
    $.secureEvalJSON = function(src)
    // Evals JSON in a way that is *more* secure.
    {
        var filtered = src;
        filtered = filtered.replace(/\\["\\\/bfnrtu]/g, '@');
        filtered = filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
        filtered = filtered.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
        
        if (/^[\],:{}\s]*$/.test(filtered))
            return eval("(" + src + ")");
        else
            throw new SyntaxError("Error parsing JSON, source is not valid.");
    };
})(jQuery);

//(c) 2008 Michael Manning 
jQuery.parseQuery = function(A, B) { var C = (typeof A === "string" ? A : window.location.search), E = { f: function(F) { return unescape(F).replace(/\+/g, " ") } }, B = (typeof A === "object" && typeof B === "undefined") ? A : B, E = jQuery.extend({}, E, B), D = {}; jQuery.each(C.match(/^\??(.*)$/)[1].split("&"), function(F, G) { G = G.split("="); G[1] = E.f(G[1]); D[G[0]] = D[G[0]] ? ((D[G[0]] instanceof Array) ? (D[G[0]].push(G[1]), D[G[0]]) : [D[G[0]], G[1]]) : G[1] }); return D };
/**
* Cookie plugin
*
* Copyright (c) 2006 Klaus Hartl (stilbuero.de)
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/

/**
* Create a cookie with the given name and value and other optional parameters.
*
* @example $.cookie('the_cookie', 'the_value');
* @desc Set the value of a cookie.
* @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
* @desc Create a cookie with all available options.
* @example $.cookie('the_cookie', 'the_value');
* @desc Create a session cookie.
* @example $.cookie('the_cookie', null);
* @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
*       used when the cookie was set.
*
* @param String name The name of the cookie.
* @param String value The value of the cookie.
* @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
* @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
*                             If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
*                             If set to null or omitted, the cookie will be a session cookie and will not be retained
*                             when the the browser exits.
* @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
* @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
* @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
*                        require a secure protocol (like HTTPS).
* @type undefined
*
* @name $.cookie
* @cat Plugins/Cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*/

/**
* Get the value of a cookie with the given name.
*
* @example $.cookie('the_cookie');
* @desc Get the value of a cookie.
*
* @param String name The name of the cookie.
* @return The value of the cookie.
* @type String
*
* @name $.cookie
* @cat Plugins/Cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*/
jQuery.cookie = function(name, value, options) {
    if (typeof value != 'undefined') { // name and value given, set cookie
        options = options || {};
        if (value === null) {
            value = '';
            options.expires = -1;
        }
        var expires = '';
        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
            var date;
            if (typeof options.expires == 'number') {
                date = new Date();
                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
            } else {
                date = options.expires;
            }
            expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
        }
        // CAUTION: Needed to parenthesize options.path and options.domain
        // in the following expressions, otherwise they evaluate to undefined
        // in the packed version for some reason...
        var path = options.path ? '; path=' + (options.path) : '';
        var domain = options.domain ? '; domain=' + (options.domain) : '';
        var secure = options.secure ? '; secure' : '';
        document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
    } else { // only name given, get cookie
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
};
/**
 *
 * Color picker
 * Author: Stefan Petre www.eyecon.ro
 * 
 * Dual licensed under the MIT and GPL licenses
 * 
 */
(function($) {
    var ColorPicker = function() {
        var 
			ids = {},
			inAction,
			charMin = 65,
			visible,
			tpl = '<div class="colorpicker"><div class="colorpicker_color"><div><div></div></div></div><div class="colorpicker_hue"><div></div></div><div class="colorpicker_new_color"></div><div class="colorpicker_current_color"></div><div class="colorpicker_hex"><input type="text" maxlength="6" size="6" /></div><div class="colorpicker_rgb_r colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_rgb_g colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_rgb_b colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_h colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_s colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_b colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_submit"></div></div>',
			defaults = {
			    eventName: 'click',
			    onShow: function() { },
			    onBeforeShow: function() { },
			    onHide: function() { },
			    onChange: function() { },
			    onSubmit: function() { },
			    color: 'ff0000',
			    livePreview: true,
			    flat: false
			},
			fillRGBFields = function(hsb, cal) {
			    var rgb = HSBToRGB(hsb);
			    $(cal).data('colorpicker').fields
					.eq(1).val(rgb.r).end()
					.eq(2).val(rgb.g).end()
					.eq(3).val(rgb.b).end();
			},
			fillHSBFields = function(hsb, cal) {
			    $(cal).data('colorpicker').fields
					.eq(4).val(hsb.h).end()
					.eq(5).val(hsb.s).end()
					.eq(6).val(hsb.b).end();
			},
			fillHexFields = function(hsb, cal) {
			    $(cal).data('colorpicker').fields
					.eq(0).val(HSBToHex(hsb)).end();
			},
			setSelector = function(hsb, cal) {
			    $(cal).data('colorpicker').selector.css('backgroundColor', '#' + HSBToHex({ h: hsb.h, s: 100, b: 100 }));
			    $(cal).data('colorpicker').selectorIndic.css({
			        left: parseInt(150 * hsb.s / 100, 10),
			        top: parseInt(150 * (100 - hsb.b) / 100, 10)
			    });
			},
			setHue = function(hsb, cal) {
			    $(cal).data('colorpicker').hue.css('top', parseInt(150 - 150 * hsb.h / 360, 10));
			},
			setCurrentColor = function(hsb, cal) {
			    $(cal).data('colorpicker').currentColor.css('backgroundColor', '#' + HSBToHex(hsb));
			},
			setNewColor = function(hsb, cal) {
			    $(cal).data('colorpicker').newColor.css('backgroundColor', '#' + HSBToHex(hsb));
			},
			keyDown = function(ev) {
			    var pressedKey = ev.charCode || ev.keyCode || -1;
			    if ((pressedKey > charMin && pressedKey <= 90) || pressedKey == 32) {
			        return false;
			    }
			    var cal = $(this).parent().parent();
			    if (cal.data('colorpicker').livePreview === true) {
			        change.apply(this);
			    }
			},
			change = function(ev) {
			    var cal = $(this).parent().parent(), col;
			    if (this.parentNode.className.indexOf('_hex') > 0) {
			        cal.data('colorpicker').color = col = HexToHSB(fixHex(this.value));
			    } else if (this.parentNode.className.indexOf('_hsb') > 0) {
			        cal.data('colorpicker').color = col = fixHSB({
			            h: parseInt(cal.data('colorpicker').fields.eq(4).val(), 10),
			            s: parseInt(cal.data('colorpicker').fields.eq(5).val(), 10),
			            b: parseInt(cal.data('colorpicker').fields.eq(6).val(), 10)
			        });
			    } else {
			        cal.data('colorpicker').color = col = RGBToHSB(fixRGB({
			            r: parseInt(cal.data('colorpicker').fields.eq(1).val(), 10),
			            g: parseInt(cal.data('colorpicker').fields.eq(2).val(), 10),
			            b: parseInt(cal.data('colorpicker').fields.eq(3).val(), 10)
			        }));
			    }
			    if (ev) {
			        fillRGBFields(col, cal.get(0));
			        fillHexFields(col, cal.get(0));
			        fillHSBFields(col, cal.get(0));
			    }
			    setSelector(col, cal.get(0));
			    setHue(col, cal.get(0));
			    setNewColor(col, cal.get(0));
			    cal.data('colorpicker').onChange.apply(cal, [col, HSBToHex(col), HSBToRGB(col)]);
			},
			blur = function(ev) {
			    var cal = $(this).parent().parent();
			    cal.data('colorpicker').fields.parent().removeClass('colorpicker_focus');
			},
			focus = function() {
			    charMin = this.parentNode.className.indexOf('_hex') > 0 ? 70 : 65;
			    $(this).parent().parent().data('colorpicker').fields.parent().removeClass('colorpicker_focus');
			    $(this).parent().addClass('colorpicker_focus');
			},
			downIncrement = function(ev) {
			    var field = $(this).parent().find('input').focus();
			    var current = {
			        el: $(this).parent().addClass('colorpicker_slider'),
			        max: this.parentNode.className.indexOf('_hsb_h') > 0 ? 360 : (this.parentNode.className.indexOf('_hsb') > 0 ? 100 : 255),
			        y: ev.pageY,
			        field: field,
			        val: parseInt(field.val(), 10),
			        preview: $(this).parent().parent().data('colorpicker').livePreview
			    };
			    $(document).bind('mouseup', current, upIncrement);
			    $(document).bind('mousemove', current, moveIncrement);
			},
			moveIncrement = function(ev) {
			    ev.data.field.val(Math.max(0, Math.min(ev.data.max, parseInt(ev.data.val + ev.pageY - ev.data.y, 10))));
			    if (ev.data.preview) {
			        change.apply(ev.data.field.get(0), [true]);
			    }
			    return false;
			},
			upIncrement = function(ev) {
			    change.apply(ev.data.field.get(0), [true]);
			    ev.data.el.removeClass('colorpicker_slider').find('input').focus();
			    $(document).unbind('mouseup', upIncrement);
			    $(document).unbind('mousemove', moveIncrement);
			    return false;
			},
			downHue = function(ev) {
			    var current = {
			        cal: $(this).parent(),
			        y: $(this).offset().top
			    };
			    current.preview = current.cal.data('colorpicker').livePreview;
			    $(document).bind('mouseup', current, upHue);
			    $(document).bind('mousemove', current, moveHue);
			},
			moveHue = function(ev) {
			    change.apply(
					ev.data.cal.data('colorpicker')
						.fields
						.eq(4)
						.val(parseInt(360 * (150 - Math.max(0, Math.min(150, (ev.pageY - ev.data.y)))) / 150, 10))
						.get(0),
					[ev.data.preview]
				);
			    return false;
			},
			upHue = function(ev) {
			    fillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
			    fillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
			    $(document).unbind('mouseup', upHue);
			    $(document).unbind('mousemove', moveHue);
			    return false;
			},
			downSelector = function(ev) {
			    var current = {
			        cal: $(this).parent(),
			        pos: $(this).offset()
			    };
			    current.preview = current.cal.data('colorpicker').livePreview;
			    $(document).bind('mouseup', current, upSelector);
			    $(document).bind('mousemove', current, moveSelector);
			},
			moveSelector = function(ev) {
			    change.apply(
					ev.data.cal.data('colorpicker')
						.fields
						.eq(6)
						.val(parseInt(100 * (150 - Math.max(0, Math.min(150, (ev.pageY - ev.data.pos.top)))) / 150, 10))
						.end()
						.eq(5)
						.val(parseInt(100 * (Math.max(0, Math.min(150, (ev.pageX - ev.data.pos.left)))) / 150, 10))
						.get(0),
					[ev.data.preview]
				);
			    return false;
			},
			upSelector = function(ev) {
			    fillRGBFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
			    fillHexFields(ev.data.cal.data('colorpicker').color, ev.data.cal.get(0));
			    $(document).unbind('mouseup', upSelector);
			    $(document).unbind('mousemove', moveSelector);
			    return false;
			},
			enterSubmit = function(ev) {
			    $(this).addClass('colorpicker_focus');
			},
			leaveSubmit = function(ev) {
			    $(this).removeClass('colorpicker_focus');
			},
			clickSubmit = function(ev) {
			    var cal = $(this).parent();
			    var col = cal.data('colorpicker').color;
			    cal.data('colorpicker').origColor = col;
			    setCurrentColor(col, cal.get(0));
			    cal.data('colorpicker').onSubmit(col, HSBToHex(col), HSBToRGB(col), cal.data('colorpicker').el);
			},
			show = function(ev) {
			    var cal = $('#' + $(this).data('colorpickerId'));
			    cal.data('colorpicker').onBeforeShow.apply(this, [cal.get(0)]);
			    var pos = $(this).offset();
			    var viewPort = getViewport();
			    var top = pos.top + this.offsetHeight;
			    var left = pos.left;
			    if (top + 176 > viewPort.t + viewPort.h) {
			        top -= this.offsetHeight + 176;
			    }
			    if (left + 356 > viewPort.l + viewPort.w) {
			        left -= 356;
			    }
			    cal.css({ left: left + 'px', top: top + 'px' });
			    if (cal.data('colorpicker').onShow.apply(this, [cal.get(0)]) != false) {
			        cal.show();
			    }
			    $(document).bind('mousedown', { cal: cal }, hide);
			    return false;
			},
			hide = function(ev) {
			    if (!isChildOf(ev.data.cal.get(0), ev.target, ev.data.cal.get(0))) {
			        if (ev.data.cal.data('colorpicker').onHide.apply(this, [ev.data.cal.get(0)]) != false) {
			            ev.data.cal.hide();
			        }
			        $(document).unbind('mousedown', hide);
			    }
			},
			isChildOf = function(parentEl, el, container) {
			    if (parentEl == el) {
			        return true;
			    }
			    if (parentEl.contains) {
			        return parentEl.contains(el);
			    }
			    if (parentEl.compareDocumentPosition) {
			        return !!(parentEl.compareDocumentPosition(el) & 16);
			    }
			    var prEl = el.parentNode;
			    while (prEl && prEl != container) {
			        if (prEl == parentEl)
			            return true;
			        prEl = prEl.parentNode;
			    }
			    return false;
			},
			getViewport = function() {
			    var m = document.compatMode == 'CSS1Compat';
			    return {
			        l: window.pageXOffset || (m ? document.documentElement.scrollLeft : document.body.scrollLeft),
			        t: window.pageYOffset || (m ? document.documentElement.scrollTop : document.body.scrollTop),
			        w: window.innerWidth || (m ? document.documentElement.clientWidth : document.body.clientWidth),
			        h: window.innerHeight || (m ? document.documentElement.clientHeight : document.body.clientHeight)
			    };
			},
			fixHSB = function(hsb) {
			    return {
			        h: Math.min(360, Math.max(0, hsb.h)),
			        s: Math.min(100, Math.max(0, hsb.s)),
			        b: Math.min(100, Math.max(0, hsb.b))
			    };
			},
			fixRGB = function(rgb) {
			    return {
			        r: Math.min(255, Math.max(0, rgb.r)),
			        g: Math.min(255, Math.max(0, rgb.g)),
			        b: Math.min(255, Math.max(0, rgb.b))
			    };
			},
			fixHex = function(hex) {
			    var len = 6 - hex.length;
			    if (len > 0) {
			        var o = [];
			        for (var i = 0; i < len; i++) {
			            o.push('0');
			        }
			        o.push(hex);
			        hex = o.join('');
			    }
			    return hex;
			},
			HexToRGB = function(hex) {
			    var hex = parseInt(((hex.indexOf('#') > -1) ? hex.substring(1) : hex), 16);
			    return { r: hex >> 16, g: (hex & 0x00FF00) >> 8, b: (hex & 0x0000FF) };
			},
			HexToHSB = function(hex) {
			    return RGBToHSB(HexToRGB(hex));
			},
			RGBToHSB = function(rgb) {
			    var hsb = {
			        h: 0,
			        s: 0,
			        b: 0
			    };
			    var min = Math.min(rgb.r, rgb.g, rgb.b);
			    var max = Math.max(rgb.r, rgb.g, rgb.b);
			    var delta = max - min;
			    hsb.b = max;
			    if (max != 0) {

			    }
			    hsb.s = max != 0 ? 255 * delta / max : 0;
			    if (hsb.s != 0) {
			        if (rgb.r == max) {
			            hsb.h = (rgb.g - rgb.b) / delta;
			        } else if (rgb.g == max) {
			            hsb.h = 2 + (rgb.b - rgb.r) / delta;
			        } else {
			            hsb.h = 4 + (rgb.r - rgb.g) / delta;
			        }
			    } else {
			        hsb.h = -1;
			    }
			    hsb.h *= 60;
			    if (hsb.h < 0) {
			        hsb.h += 360;
			    }
			    hsb.s *= 100 / 255;
			    hsb.b *= 100 / 255;
			    return hsb;
			},
			HSBToRGB = function(hsb) {
			    var rgb = {};
			    var h = Math.round(hsb.h);
			    var s = Math.round(hsb.s * 255 / 100);
			    var v = Math.round(hsb.b * 255 / 100);
			    if (s == 0) {
			        rgb.r = rgb.g = rgb.b = v;
			    } else {
			        var t1 = v;
			        var t2 = (255 - s) * v / 255;
			        var t3 = (t1 - t2) * (h % 60) / 60;
			        if (h == 360) h = 0;
			        if (h < 60) { rgb.r = t1; rgb.b = t2; rgb.g = t2 + t3 }
			        else if (h < 120) { rgb.g = t1; rgb.b = t2; rgb.r = t1 - t3 }
			        else if (h < 180) { rgb.g = t1; rgb.r = t2; rgb.b = t2 + t3 }
			        else if (h < 240) { rgb.b = t1; rgb.r = t2; rgb.g = t1 - t3 }
			        else if (h < 300) { rgb.b = t1; rgb.g = t2; rgb.r = t2 + t3 }
			        else if (h < 360) { rgb.r = t1; rgb.g = t2; rgb.b = t1 - t3 }
			        else { rgb.r = 0; rgb.g = 0; rgb.b = 0 }
			    }
			    return { r: Math.round(rgb.r), g: Math.round(rgb.g), b: Math.round(rgb.b) };
			},
			RGBToHex = function(rgb) {
			    var hex = [
					rgb.r.toString(16),
					rgb.g.toString(16),
					rgb.b.toString(16)
				];
			    $.each(hex, function(nr, val) {
			        if (val.length == 1) {
			            hex[nr] = '0' + val;
			        }
			    });
			    return hex.join('');
			},
			HSBToHex = function(hsb) {
			    return RGBToHex(HSBToRGB(hsb));
			},
			restoreOriginal = function() {
			    var cal = $(this).parent();
			    var col = cal.data('colorpicker').origColor;
			    cal.data('colorpicker').color = col;
			    fillRGBFields(col, cal.get(0));
			    fillHexFields(col, cal.get(0));
			    fillHSBFields(col, cal.get(0));
			    setSelector(col, cal.get(0));
			    setHue(col, cal.get(0));
			    setNewColor(col, cal.get(0));
			};
        return {
            init: function(opt) {
                opt = $.extend({}, defaults, opt || {});
                if (typeof opt.color == 'string') {
                    opt.color = HexToHSB(opt.color);
                } else if (opt.color.r != undefined && opt.color.g != undefined && opt.color.b != undefined) {
                    opt.color = RGBToHSB(opt.color);
                } else if (opt.color.h != undefined && opt.color.s != undefined && opt.color.b != undefined) {
                    opt.color = fixHSB(opt.color);
                } else {
                    return this;
                }
                return this.each(function() {
                    if (!$(this).data('colorpickerId')) {
                        var options = $.extend({}, opt);
                        options.origColor = opt.color;
                        var id = 'collorpicker_' + parseInt(Math.random() * 1000);
                        $(this).data('colorpickerId', id);
                        var cal = $(tpl).attr('id', id);
                        if (options.flat) {
                            cal.appendTo(this).show();
                        } else {
                            cal.appendTo(document.body);
                        }
                        options.fields = cal
											.find('input')
												.bind('keyup', keyDown)
												.bind('change', change)
												.bind('blur', blur)
												.bind('focus', focus);
                        cal
							.find('span').bind('mousedown', downIncrement).end()
							.find('>div.colorpicker_current_color').bind('click', restoreOriginal);
                        options.selector = cal.find('div.colorpicker_color').bind('mousedown', downSelector);
                        options.selectorIndic = options.selector.find('div div');
                        options.el = this;
                        options.hue = cal.find('div.colorpicker_hue div');
                        cal.find('div.colorpicker_hue').bind('mousedown', downHue);
                        options.newColor = cal.find('div.colorpicker_new_color');
                        options.currentColor = cal.find('div.colorpicker_current_color');
                        cal.data('colorpicker', options);
                        cal.find('div.colorpicker_submit')
							.bind('mouseenter', enterSubmit)
							.bind('mouseleave', leaveSubmit)
							.bind('click', clickSubmit);
                        fillRGBFields(options.color, cal.get(0));
                        fillHSBFields(options.color, cal.get(0));
                        fillHexFields(options.color, cal.get(0));
                        setHue(options.color, cal.get(0));
                        setSelector(options.color, cal.get(0));
                        setCurrentColor(options.color, cal.get(0));
                        setNewColor(options.color, cal.get(0));
                        if (options.flat) {
                            cal.css({
                                position: 'relative',
                                display: 'block'
                            });
                        } else {
                            $(this).bind(options.eventName, show);
                        }
                    }
                });
            },
            showPicker: function() {
                return this.each(function() {
                    if ($(this).data('colorpickerId')) {
                        show.apply(this);
                    }
                });
            },
            hidePicker: function() {
                return this.each(function() {
                    if ($(this).data('colorpickerId')) {
                        $('#' + $(this).data('colorpickerId')).hide();
                    }
                });
            },
            setColor: function(col) {
                if (typeof col == 'string') {
                    col = HexToHSB(col);
                } else if (col.r != undefined && col.g != undefined && col.b != undefined) {
                    col = RGBToHSB(col);
                } else if (col.h != undefined && col.s != undefined && col.b != undefined) {
                    col = fixHSB(col);
                } else {
                    return this;
                }
                return this.each(function() {
                    if ($(this).data('colorpickerId')) {
                        var cal = $('#' + $(this).data('colorpickerId'));
                        cal.data('colorpicker').color = col;
                        cal.data('colorpicker').origColor = col;
                        fillRGBFields(col, cal.get(0));
                        fillHSBFields(col, cal.get(0));
                        fillHexFields(col, cal.get(0));
                        setHue(col, cal.get(0));
                        setSelector(col, cal.get(0));
                        setCurrentColor(col, cal.get(0));
                        setNewColor(col, cal.get(0));
                    }
                });
            }
        };
    } ();
    $.fn.extend({
        ColorPicker: ColorPicker.init,
        ColorPickerHide: ColorPicker.hidePicker,
        ColorPickerShow: ColorPicker.showPicker,
        ColorPickerSetColor: ColorPicker.setColor
    });
})(jQuery);
/* Javascript plotting library for jQuery, v. 0.5.
 *
 * Released under the MIT license by IOLA, December 2007.
 *
 */

(function($) {
    function Plot(target_, data_, options_) {
        // data is on the form:
        //   [ series1, series2 ... ]
        // where series is either just the data as [ [x1, y1], [x2, y2], ... ]
        // or { data: [ [x1, y1], [x2, y2], ... ], label: "some label" }
        
        var series = [],
            options = {
            // the color theme used for graphs
            colors: ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"],
                legend: {
                    show: true,
                    noColumns: 1, // number of colums in legend table
                    labelFormatter: null, // fn: string -> string
                    labelBoxBorderColor: "#ccc", // border color for the little label boxes
                    container: null, // container (as jQuery object) to put legend in, null means default on top of graph
                    position: "ne", // position of default legend container within plot
                    margin: 5, // distance from grid edge to default legend container within plot
                    backgroundColor: null, // null means auto-detect
                    backgroundOpacity: 0.85 // set to 0 to avoid background
                },
                xaxis: {
                    mode: null, // null or "time"
                    min: null, // min. value to show, null means set automatically
                    max: null, // max. value to show, null means set automatically
                    autoscaleMargin: null, // margin in % to add if auto-setting min/max
                    ticks: null, // either [1, 3] or [[1, "a"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks
                    tickFormatter: null, // fn: number -> string
                    labelWidth: null, // size of tick labels in pixels
                    labelHeight: null,
                    
                    // mode specific options
                    tickDecimals: null, // no. of decimals, null means auto
                    tickSize: null, // number or [number, "unit"]
                    minTickSize: null, // number or [number, "unit"]
                    monthNames: null, // list of names of months
                    timeformat: null // format string to use
                },
                yaxis: {
                    autoscaleMargin: 0.02
                },
                x2axis: {
                    autoscaleMargin: null
                },
                y2axis: {
                    autoscaleMargin: 0.02
                },              
                points: {
                    show: false,
                    radius: 3,
                    lineWidth: 2, // in pixels
                    fill: true,
                    fillColor: "#ffffff"
                },
                lines: {
                    show: false,
                    lineWidth: 2, // in pixels
                    fill: false,
                    fillColor: null
                },
                bars: {
                    show: false,
                    lineWidth: 2, // in pixels
                    barWidth: 1, // in units of the x axis
                    fill: true,
                    fillColor: null,
                    align: "left" // or "center"
                },
                grid: {
                    color: "#545454", // primary color used for outline and labels
                    backgroundColor: null, // null for transparent, else color
                    tickColor: "#dddddd", // color used for the ticks
                    labelMargin: 5, // in pixels
                    borderWidth: 2,
                    markings: null, // array of ranges or fn: axes -> array of ranges
                    markingsColor: "#f4f4f4",
                    markingsLineWidth: 2,
                    // interactive stuff
                    clickable: false,
                    hoverable: false,
                    autoHighlight: true, // highlight in case mouse is near
                    mouseActiveRadius: 10 // how far the mouse can be away to activate an item
                },
                selection: {
                    mode: null, // one of null, "x", "y" or "xy"
                    color: "#e8cfac"
                },
                shadowSize: 4
            },
        canvas = null,      // the canvas for the plot itself
        overlay = null,     // canvas for interactive stuff on top of plot
        eventHolder = null, // jQuery object that events should be bound to
        ctx = null, octx = null,
        target = target_,
        axes = { xaxis: {}, yaxis: {}, x2axis: {}, y2axis: {} },
        plotOffset = { left: 0, right: 0, top: 0, bottom: 0},
        canvasWidth = 0, canvasHeight = 0,
        plotWidth = 0, plotHeight = 0,
        // dedicated to storing data for buggy standard compliance cases
        workarounds = {};
        
        this.setData = setData;
        this.setupGrid = setupGrid;
        this.draw = draw;
        this.clearSelection = clearSelection;
        this.setSelection = setSelection;
        this.getCanvas = function() { return canvas; };
        this.getPlotOffset = function() { return plotOffset; };
        this.getData = function() { return series; };
        this.getAxes = function() { return axes; };
        this.highlight = highlight;
        this.unhighlight = unhighlight;
        
        // initialize
        parseOptions(options_);
        setData(data_);
        constructCanvas();
        setupGrid();
        draw();


        function setData(d) {
            series = parseData(d);

            fillInSeriesOptions();
            processData();
        }
        
        function parseData(d) {
            var res = [];
            for (var i = 0; i < d.length; ++i) {
                var s;
                if (d[i].data) {
                    s = {};
                    for (var v in d[i])
                        s[v] = d[i][v];
                }
                else {
                    s = { data: d[i] };
                }
                res.push(s);
            }

            return res;
        }
        
        function parseOptions(o) {
            $.extend(true, options, o);

            // backwards compatibility, to be removed in future
            if (options.xaxis.noTicks && options.xaxis.ticks == null)
                options.xaxis.ticks = options.xaxis.noTicks;
            if (options.yaxis.noTicks && options.yaxis.ticks == null)
                options.yaxis.ticks = options.yaxis.noTicks;
            if (options.grid.coloredAreas)
                options.grid.markings = options.grid.coloredAreas;
            if (options.grid.coloredAreasColor)
                options.grid.markingsColor = options.grid.coloredAreasColor;
        }

        function fillInSeriesOptions() {
            var i;
            
            // collect what we already got of colors
            var neededColors = series.length,
                usedColors = [],
                assignedColors = [];
            for (i = 0; i < series.length; ++i) {
                var sc = series[i].color;
                if (sc != null) {
                    --neededColors;
                    if (typeof sc == "number")
                        assignedColors.push(sc);
                    else
                        usedColors.push(parseColor(series[i].color));
                }
            }
            
            // we might need to generate more colors if higher indices
            // are assigned
            for (i = 0; i < assignedColors.length; ++i) {
                neededColors = Math.max(neededColors, assignedColors[i] + 1);
            }

            // produce colors as needed
            var colors = [], variation = 0;
            i = 0;
            while (colors.length < neededColors) {
                var c;
                if (options.colors.length == i) // check degenerate case
                    c = new Color(100, 100, 100);
                else
                    c = parseColor(options.colors[i]);

                // vary color if needed
                var sign = variation % 2 == 1 ? -1 : 1;
                var factor = 1 + sign * Math.ceil(variation / 2) * 0.2;
                c.scale(factor, factor, factor);

                // FIXME: if we're getting to close to something else,
                // we should probably skip this one
                colors.push(c);
                
                ++i;
                if (i >= options.colors.length) {
                    i = 0;
                    ++variation;
                }
            }

            // fill in the options
            var colori = 0, s;
            for (i = 0; i < series.length; ++i) {
                s = series[i];

                // assign colors
                if (s.color == null) {
                    s.color = colors[colori].toString();
                    ++colori;
                }
                else if (typeof s.color == "number")
                    s.color = colors[s.color].toString();

                // copy the rest
                s.lines = $.extend(true, {}, options.lines, s.lines);
                s.points = $.extend(true, {}, options.points, s.points);
                s.bars = $.extend(true, {}, options.bars, s.bars);
                if (s.shadowSize == null)
                    s.shadowSize = options.shadowSize;
                if (s.xaxis && s.xaxis == 2)
                    s.xaxis = axes.x2axis;
                else
                    s.xaxis = axes.xaxis;
                if (s.yaxis && s.yaxis == 2)
                    s.yaxis = axes.y2axis;
                else
                    s.yaxis = axes.yaxis;
            }
        }
        
        function processData() {
            var topSentry = Number.POSITIVE_INFINITY,
                bottomSentry = Number.NEGATIVE_INFINITY,
                axis;

            for (axis in axes) {
                axes[axis].datamin = topSentry;
                axes[axis].datamax = bottomSentry;
                axes[axis].used = false;
            }
            
            for (var i = 0; i < series.length; ++i) {
                var data = series[i].data,
                    axisx = series[i].xaxis,
                    axisy = series[i].yaxis,
                    mindelta = 0, maxdelta = 0;
                
                // make sure we got room for the bar
                if (series[i].bars.show) {
                    mindelta = series[i].bars.align == "left" ? 0 : -series[i].bars.barWidth/2;
                    maxdelta = mindelta + series[i].bars.barWidth;
                }
                
                axisx.used = axisy.used = true;
                for (var j = 0; j < data.length; ++j) {
                    if (data[j] == null)
                        continue;
                    
                    var x = data[j][0], y = data[j][1];

                    // convert to number
                    if (x != null && !isNaN(x = +x)) {
                        if (x + mindelta < axisx.datamin)
                            axisx.datamin = x + mindelta;
                        if (x + maxdelta > axisx.datamax)
                            axisx.datamax = x + maxdelta;
                    }
                    
                    if (y != null && !isNaN(y = +y)) {
                        if (y < axisy.datamin)
                            axisy.datamin = y;
                        if (y > axisy.datamax)
                            axisy.datamax = y;
                    }
                    
                    if (x == null || y == null || isNaN(x) || isNaN(y))
                        data[j] = null; // mark this point as invalid
                }
            }

            for (axis in axes) {
                if (axes[axis].datamin == topSentry)
                    axes[axis].datamin = 0;
                if (axes[axis].datamax == bottomSentry)
                    axes[axis].datamax = 1;
            }
        }

        function constructCanvas() {
            canvasWidth = target.width();
            canvasHeight = target.height();
            target.html(""); // clear target
            target.css("position", "relative"); // for positioning labels and overlay

            if (canvasWidth <= 0 || canvasHeight <= 0)
                throw "Invalid dimensions for plot, width = " + canvasWidth + ", height = " + canvasHeight;

            // the canvas
            canvas = $('<canvas width="' + canvasWidth + '" height="' + canvasHeight + '"></canvas>').appendTo(target).get(0);
            if ($.browser.msie) // excanvas hack
                canvas = window.G_vmlCanvasManager.initElement(canvas);
            ctx = canvas.getContext("2d");

            // overlay canvas for interactive features
            overlay = $('<canvas style="position:absolute;left:0px;top:0px;" width="' + canvasWidth + '" height="' + canvasHeight + '"></canvas>').appendTo(target).get(0);
            if ($.browser.msie) // excanvas hack
                overlay = window.G_vmlCanvasManager.initElement(overlay);
            octx = overlay.getContext("2d");

            // we include the canvas in the event holder too, because IE 7
            // sometimes has trouble with the stacking order
            eventHolder = $([overlay, canvas]);

            // bind events
            if (options.selection.mode != null || options.grid.hoverable) {
                // FIXME: temp. work-around until jQuery bug 1871 is fixed
                eventHolder.each(function () {
                    this.onmousemove = onMouseMove;
                });

                if (options.selection.mode != null)
                    eventHolder.mousedown(onMouseDown);
            }

            if (options.grid.clickable)
                eventHolder.click(onClick);
        }

        function setupGrid() {
            function setupAxis(axis, options) {
                setRange(axis, options);
                prepareTickGeneration(axis, options);
                setTicks(axis, options);
                // add transformation helpers
                if (axis == axes.xaxis || axis == axes.x2axis) {
                    // data point to canvas coordinate
                    axis.p2c = function (p) { return (p - axis.min) * axis.scale; };
                    // canvas coordinate to data point 
                    axis.c2p = function (c) { return axis.min + c / axis.scale; };
                }
                else {
                    axis.p2c = function (p) { return (axis.max - p) * axis.scale; };
                    axis.c2p = function (p) { return axis.max - p / axis.scale; };
                }
            }

            for (var axis in axes)
                setupAxis(axes[axis], options[axis]);

            setSpacing();
            insertLabels();
            insertLegend();
        }
        
        function setRange(axis, axisOptions) {
            var min = axisOptions.min != null ? axisOptions.min : axis.datamin;
            var max = axisOptions.max != null ? axisOptions.max : axis.datamax;

            if (max - min == 0.0) {
                // degenerate case
                var widen;
                if (max == 0.0)
                    widen = 1.0;
                else
                    widen = 0.01;

                min -= widen;
                max += widen;
            }
            else {
                // consider autoscaling
                var margin = axisOptions.autoscaleMargin;
                if (margin != null) {
                    if (axisOptions.min == null) {
                        min -= (max - min) * margin;
                        // make sure we don't go below zero if all values
                        // are positive
                        if (min < 0 && axis.datamin >= 0)
                            min = 0;
                    }
                    if (axisOptions.max == null) {
                        max += (max - min) * margin;
                        if (max > 0 && axis.datamax <= 0)
                            max = 0;
                    }
                }
            }
            axis.min = min;
            axis.max = max;
        }

        function prepareTickGeneration(axis, axisOptions) {
            // estimate number of ticks
            var noTicks;
            if (typeof axisOptions.ticks == "number" && axisOptions.ticks > 0)
                noTicks = axisOptions.ticks;
            else if (axis == axes.xaxis || axis == axes.x2axis)
                noTicks = canvasWidth / 100;
            else
                noTicks = canvasHeight / 60;
            
            var delta = (axis.max - axis.min) / noTicks;
            var size, generator, unit, formatter, i, magn, norm;

            if (axisOptions.mode == "time") {
                // pretty handling of time
                
                function formatDate(d, fmt, monthNames) {
                    var leftPad = function(n) {
                        n = "" + n;
                        return n.length == 1 ? "0" + n : n;
                    };
                    
                    var r = [];
                    var escape = false;
                    if (monthNames == null)
                        monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
                    for (var i = 0; i < fmt.length; ++i) {
                        var c = fmt.charAt(i);
                        
                        if (escape) {
                            switch (c) {
                            case 'h': c = "" + d.getUTCHours(); break;
                            case 'H': c = leftPad(d.getUTCHours()); break;
                            case 'M': c = leftPad(d.getUTCMinutes()); break;
                            case 'S': c = leftPad(d.getUTCSeconds()); break;
                            case 'd': c = "" + d.getUTCDate(); break;
                            case 'm': c = "" + (d.getUTCMonth() + 1); break;
                            case 'y': c = "" + d.getUTCFullYear(); break;
                            case 'b': c = "" + monthNames[d.getUTCMonth()]; break;
                            }
                            r.push(c);
                            escape = false;
                        }
                        else {
                            if (c == "%")
                                escape = true;
                            else
                                r.push(c);
                        }
                    }
                    return r.join("");
                }
                
                    
                // map of app. size of time units in milliseconds
                var timeUnitSize = {
                    "second": 1000,
                    "minute": 60 * 1000,
                    "hour": 60 * 60 * 1000,
                    "day": 24 * 60 * 60 * 1000,
                    "month": 30 * 24 * 60 * 60 * 1000,
                    "year": 365.2425 * 24 * 60 * 60 * 1000
                };


                // the allowed tick sizes, after 1 year we use
                // an integer algorithm
                var spec = [
                    [1, "second"], [2, "second"], [5, "second"], [10, "second"],
                    [30, "second"], 
                    [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"],
                    [30, "minute"], 
                    [1, "hour"], [2, "hour"], [4, "hour"],
                    [8, "hour"], [12, "hour"],
                    [1, "day"], [2, "day"], [3, "day"],
                    [0.25, "month"], [0.5, "month"], [1, "month"],
                    [2, "month"], [3, "month"], [6, "month"],
                    [1, "year"]
                ];

                var minSize = 0;
                if (axisOptions.minTickSize != null) {
                    if (typeof axisOptions.tickSize == "number")
                        minSize = axisOptions.tickSize;
                    else
                        minSize = axisOptions.minTickSize[0] * timeUnitSize[axisOptions.minTickSize[1]];
                }

                for (i = 0; i < spec.length - 1; ++i)
                    if (delta < (spec[i][0] * timeUnitSize[spec[i][1]]
                                 + spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2
                       && spec[i][0] * timeUnitSize[spec[i][1]] >= minSize)
                        break;
                size = spec[i][0];
                unit = spec[i][1];
                
                // special-case the possibility of several years
                if (unit == "year") {
                    magn = Math.pow(10, Math.floor(Math.log(delta / timeUnitSize.year) / Math.LN10));
                    norm = (delta / timeUnitSize.year) / magn;
                    if (norm < 1.5)
                        size = 1;
                    else if (norm < 3)
                        size = 2;
                    else if (norm < 7.5)
                        size = 5;
                    else
                        size = 10;

                    size *= magn;
                }

                if (axisOptions.tickSize) {
                    size = axisOptions.tickSize[0];
                    unit = axisOptions.tickSize[1];
                }
                
                generator = function(axis) {
                    var ticks = [],
                        tickSize = axis.tickSize[0], unit = axis.tickSize[1],
                        d = new Date(axis.min);
                    
                    var step = tickSize * timeUnitSize[unit];

                    if (unit == "second")
                        d.setUTCSeconds(floorInBase(d.getUTCSeconds(), tickSize));
                    if (unit == "minute")
                        d.setUTCMinutes(floorInBase(d.getUTCMinutes(), tickSize));
                    if (unit == "hour")
                        d.setUTCHours(floorInBase(d.getUTCHours(), tickSize));
                    if (unit == "month")
                        d.setUTCMonth(floorInBase(d.getUTCMonth(), tickSize));
                    if (unit == "year")
                        d.setUTCFullYear(floorInBase(d.getUTCFullYear(), tickSize));
                    
                    // reset smaller components
                    d.setUTCMilliseconds(0);
                    if (step >= timeUnitSize.minute)
                        d.setUTCSeconds(0);
                    if (step >= timeUnitSize.hour)
                        d.setUTCMinutes(0);
                    if (step >= timeUnitSize.day)
                        d.setUTCHours(0);
                    if (step >= timeUnitSize.day * 4)
                        d.setUTCDate(1);
                    if (step >= timeUnitSize.year)
                        d.setUTCMonth(0);


                    var carry = 0, v = Number.NaN, prev;
                    do {
                        prev = v;
                        v = d.getTime();
                        ticks.push({ v: v, label: axis.tickFormatter(v, axis) });
                        if (unit == "month") {
                            if (tickSize < 1) {
                                // a bit complicated - we'll divide the month
                                // up but we need to take care of fractions
                                // so we don't end up in the middle of a day
                                d.setUTCDate(1);
                                var start = d.getTime();
                                d.setUTCMonth(d.getUTCMonth() + 1);
                                var end = d.getTime();
                                d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize);
                                carry = d.getUTCHours();
                                d.setUTCHours(0);
                            }
                            else
                                d.setUTCMonth(d.getUTCMonth() + tickSize);
                        }
                        else if (unit == "year") {
                            d.setUTCFullYear(d.getUTCFullYear() + tickSize);
                        }
                        else
                            d.setTime(v + step);
                    } while (v < axis.max && v != prev);

                    return ticks;
                };

                formatter = function (v, axis) {
                    var d = new Date(v);

                    // first check global format
                    if (axisOptions.timeformat != null)
                        return formatDate(d, axisOptions.timeformat, axisOptions.monthNames);
                    
                    var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]];
                    var span = axis.max - axis.min;
                    
                    if (t < timeUnitSize.minute)
                        fmt = "%h:%M:%S";
                    else if (t < timeUnitSize.day) {
                        if (span < 2 * timeUnitSize.day)
                            fmt = "%h:%M";
                        else
                            fmt = "%b %d %h:%M";
                    }
                    else if (t < timeUnitSize.month)
                        fmt = "%b %d";
                    else if (t < timeUnitSize.year) {
                        if (span < timeUnitSize.year)
                            fmt = "%b";
                        else
                            fmt = "%b %y";
                    }
                    else
                        fmt = "%y";
                    
                    return formatDate(d, fmt, axisOptions.monthNames);
                };
            }
            else {
                // pretty rounding of base-10 numbers
                var maxDec = axisOptions.tickDecimals;
                var dec = -Math.floor(Math.log(delta) / Math.LN10);
                if (maxDec != null && dec > maxDec)
                    dec = maxDec;
                
                magn = Math.pow(10, -dec);
                norm = delta / magn; // norm is between 1.0 and 10.0
                
                if (norm < 1.5)
                    size = 1;
                else if (norm < 3) {
                    size = 2;
                    // special case for 2.5, requires an extra decimal
                    if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) {
                        size = 2.5;
                        ++dec;
                    }
                }
                else if (norm < 7.5)
                    size = 5;
                else
                    size = 10;

                size *= magn;
                
                if (axisOptions.minTickSize != null && size < axisOptions.minTickSize)
                    size = axisOptions.minTickSize;

                if (axisOptions.tickSize != null)
                    size = axisOptions.tickSize;
                
                axis.tickDecimals = Math.max(0, (maxDec != null) ? maxDec : dec);
                
                generator = function (axis) {
                    var ticks = [];

                    // spew out all possible ticks
                    var start = floorInBase(axis.min, axis.tickSize),
                        i = 0, v = Number.NaN, prev;
                    do {
                        prev = v;
                        v = start + i * axis.tickSize;
                        ticks.push({ v: v, label: axis.tickFormatter(v, axis) });
                        ++i;
                    } while (v < axis.max && v != prev);
                    return ticks;
                };

                formatter = function (v, axis) {
                    return v.toFixed(axis.tickDecimals);
                };
            }

            axis.tickSize = unit ? [size, unit] : size;
            axis.tickGenerator = generator;
            if ($.isFunction(axisOptions.tickFormatter))
                axis.tickFormatter = function (v, axis) { return "" + axisOptions.tickFormatter(v, axis); };
            else
                axis.tickFormatter = formatter;
            if (axisOptions.labelWidth != null)
                axis.labelWidth = axisOptions.labelWidth;
            if (axisOptions.labelHeight != null)
                axis.labelHeight = axisOptions.labelHeight;
        }
        
        function setTicks(axis, axisOptions) {
            axis.ticks = [];

            if (!axis.used)
                return;
            
            if (axisOptions.ticks == null)
                axis.ticks = axis.tickGenerator(axis);
            else if (typeof axisOptions.ticks == "number") {
                if (axisOptions.ticks > 0)
                    axis.ticks = axis.tickGenerator(axis);
            }
            else if (axisOptions.ticks) {
                var ticks = axisOptions.ticks;

                if ($.isFunction(ticks))
                    // generate the ticks
                    ticks = ticks({ min: axis.min, max: axis.max });
                
                // clean up the user-supplied ticks, copy them over
                var i, v;
                for (i = 0; i < ticks.length; ++i) {
                    var label = null;
                    var t = ticks[i];
                    if (typeof t == "object") {
                        v = t[0];
                        if (t.length > 1)
                            label = t[1];
                    }
                    else
                        v = t;
                    if (label == null)
                        label = axis.tickFormatter(v, axis);
                    axis.ticks[i] = { v: v, label: label };
                }
            }

            if (axisOptions.autoscaleMargin != null && axis.ticks.length > 0) {
                // snap to ticks
                if (axisOptions.min == null)
                    axis.min = Math.min(axis.min, axis.ticks[0].v);
                if (axisOptions.max == null && axis.ticks.length > 1)
                    axis.max = Math.min(axis.max, axis.ticks[axis.ticks.length - 1].v);
            }
        }
        
        function setSpacing() {
            function measureXLabels(axis) {
                // to avoid measuring the widths of the labels, we
                // construct fixed-size boxes and put the labels inside
                // them, we don't need the exact figures and the
                // fixed-size box content is easy to center
                if (axis.labelWidth == null)
                    axis.labelWidth = canvasWidth / 6;

                // measure x label heights
                if (axis.labelHeight == null) {
                    labels = [];
                    for (i = 0; i < axis.ticks.length; ++i) {
                        l = axis.ticks[i].label;
                        if (l)
                            labels.push('<div class="tickLabel" style="float:left;width:' + axis.labelWidth + 'px">' + l + '</div>');
                    }
                    
                    axis.labelHeight = 0;
                    if (labels.length > 0) {
                        var dummyDiv = $('<div style="position:absolute;top:-10000px;width:10000px;font-size:smaller">'
                                         + labels.join("") + '<div style="clear:left"></div></div>').appendTo(target);
                        axis.labelHeight = dummyDiv.height();
                        dummyDiv.remove();
                    }
                }
            }
            
            function measureYLabels(axis) {
                if (axis.labelWidth == null || axis.labelHeight == null) {
                    var i, labels = [], l;
                    // calculate y label dimensions
                    for (i = 0; i < axis.ticks.length; ++i) {
                        l = axis.ticks[i].label;
                        if (l)
                            labels.push('<div class="tickLabel">' + l + '</div>');
                    }
                    
                    if (labels.length > 0) {
                        var dummyDiv = $('<div style="position:absolute;top:-10000px;font-size:smaller">'
                                         + labels.join("") + '</div>').appendTo(target);
                        if (axis.labelWidth == null)
                            axis.labelWidth = dummyDiv.width();
                        if (axis.labelHeight == null)
                            axis.labelHeight = dummyDiv.find("div").height();
                        dummyDiv.remove();
                    }
                    
                    if (axis.labelWidth == null)
                        axis.labelWidth = 0;
                    if (axis.labelHeight == null)
                        axis.labelHeight = 0;
                }
            }
            
            measureXLabels(axes.xaxis);
            measureYLabels(axes.yaxis);
            measureXLabels(axes.x2axis);
            measureYLabels(axes.y2axis);

            // get the most space needed around the grid for things
            // that may stick out
            var maxOutset = options.grid.borderWidth / 2;
            for (i = 0; i < series.length; ++i)
                maxOutset = Math.max(maxOutset, 2 * (series[i].points.radius + series[i].points.lineWidth/2));

            plotOffset.left = plotOffset.right = plotOffset.top = plotOffset.bottom = maxOutset;

            if (axes.xaxis.labelHeight > 0)
                plotOffset.bottom = Math.max(maxOutset, axes.xaxis.labelHeight + options.grid.labelMargin);
            if (axes.yaxis.labelWidth > 0)
                plotOffset.left = Math.max(maxOutset, axes.yaxis.labelWidth + options.grid.labelMargin);

            if (axes.x2axis.labelHeight > 0)
                plotOffset.top = Math.max(maxOutset, axes.x2axis.labelHeight + options.grid.labelMargin);
            
            if (axes.y2axis.labelWidth > 0)
                plotOffset.right = Math.max(maxOutset, axes.y2axis.labelWidth + options.grid.labelMargin);

            plotWidth = canvasWidth - plotOffset.left - plotOffset.right;
            plotHeight = canvasHeight - plotOffset.bottom - plotOffset.top;

            // precompute how much the axis is scaling a point in canvas space
            axes.xaxis.scale = plotWidth / (axes.xaxis.max - axes.xaxis.min);
            axes.yaxis.scale = plotHeight / (axes.yaxis.max - axes.yaxis.min);
            axes.x2axis.scale = plotWidth / (axes.x2axis.max - axes.x2axis.min);
            axes.y2axis.scale = plotHeight / (axes.y2axis.max - axes.y2axis.min);
        }
        
        function draw() {
            drawGrid();
            for (var i = 0; i < series.length; i++) {
                drawSeries(series[i]);
            }
        }

        function extractRange(ranges, coord) {
            var firstAxis = coord + "axis",
                secondaryAxis = coord + "2axis",
                axis, from, to, reverse;

            if (ranges[firstAxis]) {
                axis = axes[firstAxis];
                from = ranges[firstAxis].from;
                to = ranges[firstAxis].to;
            }
            else if (ranges[secondaryAxis]) {
                axis = axes[secondaryAxis];
                from = ranges[secondaryAxis].from;
                to = ranges[secondaryAxis].to;
            }
            else {
                // backwards-compat stuff - to be removed in future
                axis = axes[firstAxis];
                from = ranges[coord + "1"];
                to = ranges[coord + "2"];
            }

            // auto-reverse as an added bonus
            if (from != null && to != null && from > to)
                return { from: to, to: from, axis: axis };
            
            return { from: from, to: to, axis: axis };
        }
        
        function drawGrid() {
            var i;
            
            ctx.save();
            ctx.clearRect(0, 0, canvasWidth, canvasHeight);
            ctx.translate(plotOffset.left, plotOffset.top);

            // draw background, if any
            if (options.grid.backgroundColor) {
                ctx.fillStyle = options.grid.backgroundColor;
                ctx.fillRect(0, 0, plotWidth, plotHeight);
            }

            // draw markings
            if (options.grid.markings) {
                var markings = options.grid.markings;
                if ($.isFunction(markings))
                    // xmin etc. are backwards-compatible, to be removed in future
                    markings = markings({ xmin: axes.xaxis.min, xmax: axes.xaxis.max, ymin: axes.yaxis.min, ymax: axes.yaxis.max, xaxis: axes.xaxis, yaxis: axes.yaxis, x2axis: axes.x2axis, y2axis: axes.y2axis });

                for (i = 0; i < markings.length; ++i) {
                    var m = markings[i],
                        xrange = extractRange(m, "x"),
                        yrange = extractRange(m, "y");

                    // fill in missing
                    if (xrange.from == null)
                        xrange.from = xrange.axis.min;
                    if (xrange.to == null)
                        xrange.to = xrange.axis.max;
                    if (yrange.from == null)
                        yrange.from = yrange.axis.min;
                    if (yrange.to == null)
                        yrange.to = yrange.axis.max;

                    // clip
                    if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max ||
                        yrange.to < yrange.axis.min || yrange.from > yrange.axis.max)
                        continue;

                    xrange.from = Math.max(xrange.from, xrange.axis.min);
                    xrange.to = Math.min(xrange.to, xrange.axis.max);
                    yrange.from = Math.max(yrange.from, yrange.axis.min);
                    yrange.to = Math.min(yrange.to, yrange.axis.max);

                    if (xrange.from == xrange.to && yrange.from == yrange.to)
                        continue;

                    // then draw
                    xrange.from = xrange.axis.p2c(xrange.from);
                    xrange.to = xrange.axis.p2c(xrange.to);
                    yrange.from = yrange.axis.p2c(yrange.from);
                    yrange.to = yrange.axis.p2c(yrange.to);
                    
                    if (xrange.from == xrange.to || yrange.from == yrange.to) {
                        // draw line
                        ctx.strokeStyle = m.color || options.grid.markingsColor;
                        ctx.lineWidth = m.lineWidth || options.grid.markingsLineWidth;
                        ctx.moveTo(Math.floor(xrange.from), Math.floor(yrange.from));
                        ctx.lineTo(Math.floor(xrange.to), Math.floor(yrange.to));
                        ctx.stroke();
                    }
                    else {
                        // fill area
                        ctx.fillStyle = m.color || options.grid.markingsColor;
                        ctx.fillRect(Math.floor(xrange.from),
                                     Math.floor(yrange.to),
                                     Math.floor(xrange.to - xrange.from),
                                     Math.floor(yrange.from - yrange.to));
                    }
                }
            }
            
            // draw the inner grid
            ctx.lineWidth = 1;
            ctx.strokeStyle = options.grid.tickColor;
            ctx.beginPath();
            var v, axis = axes.xaxis;
            for (i = 0; i < axis.ticks.length; ++i) {
                v = axis.ticks[i].v;
                if (v <= axis.min || v >= axes.xaxis.max)
                    continue;   // skip those lying on the axes

                ctx.moveTo(Math.floor(axis.p2c(v)) + ctx.lineWidth/2, 0);
                ctx.lineTo(Math.floor(axis.p2c(v)) + ctx.lineWidth/2, plotHeight);
            }

            axis = axes.yaxis;
            for (i = 0; i < axis.ticks.length; ++i) {
                v = axis.ticks[i].v;
                if (v <= axis.min || v >= axis.max)
                    continue;

                ctx.moveTo(0, Math.floor(axis.p2c(v)) + ctx.lineWidth/2);
                ctx.lineTo(plotWidth, Math.floor(axis.p2c(v)) + ctx.lineWidth/2);
            }

            axis = axes.x2axis;
            for (i = 0; i < axis.ticks.length; ++i) {
                v = axis.ticks[i].v;
                if (v <= axis.min || v >= axis.max)
                    continue;
    
                ctx.moveTo(Math.floor(axis.p2c(v)) + ctx.lineWidth/2, -5);
                ctx.lineTo(Math.floor(axis.p2c(v)) + ctx.lineWidth/2, 5);
            }

            axis = axes.y2axis;
            for (i = 0; i < axis.ticks.length; ++i) {
                v = axis.ticks[i].v;
                if (v <= axis.min || v >= axis.max)
                    continue;

                ctx.moveTo(plotWidth-5, Math.floor(axis.p2c(v)) + ctx.lineWidth/2);
                ctx.lineTo(plotWidth+5, Math.floor(axis.p2c(v)) + ctx.lineWidth/2);
            }
            
            ctx.stroke();
            
            if (options.grid.borderWidth) {
                // draw border
                ctx.lineWidth = options.grid.borderWidth;
                ctx.strokeStyle = options.grid.color;
                ctx.lineJoin = "round";
                ctx.strokeRect(0, 0, plotWidth, plotHeight);
            }

            ctx.restore();
        }
        
        function insertLabels() {
            target.find(".tickLabels").remove();
            
            var html = '<div class="tickLabels" style="font-size:smaller;color:' + options.grid.color + '">';

            function addLabels(axis, labelGenerator) {
                for (var i = 0; i < axis.ticks.length; ++i) {
                    var tick = axis.ticks[i];
                    if (!tick.label || tick.v < axis.min || tick.v > axis.max)
                        continue;
                    html += labelGenerator(tick, axis);
                }
            }
            
            addLabels(axes.xaxis, function (tick, axis) {
                return '<div style="position:absolute;top:' + (plotOffset.top + plotHeight + options.grid.labelMargin) + 'px;left:' + (plotOffset.left + axis.p2c(tick.v) - axis.labelWidth/2) + 'px;width:' + axis.labelWidth + 'px;text-align:center" class="tickLabel">' + tick.label + "</div>";
            });
            
            
            addLabels(axes.yaxis, function (tick, axis) {
                return '<div style="position:absolute;top:' + (plotOffset.top + axis.p2c(tick.v) - axis.labelHeight/2) + 'px;right:' + (plotOffset.right + plotWidth + options.grid.labelMargin) + 'px;width:' + axis.labelWidth + 'px;text-align:right" class="tickLabel">' + tick.label + "</div>";
            });
            
            addLabels(axes.x2axis, function (tick, axis) {
                return '<div style="position:absolute;bottom:' + (plotOffset.bottom + plotHeight + options.grid.labelMargin) + 'px;left:' + (plotOffset.left + axis.p2c(tick.v) - axis.labelWidth/2) + 'px;width:' + axis.labelWidth + 'px;text-align:center" class="tickLabel">' + tick.label + "</div>";
            });
            
            addLabels(axes.y2axis, function (tick, axis) {
                return '<div style="position:absolute;top:' + (plotOffset.top + axis.p2c(tick.v) - axis.labelHeight/2) + 'px;left:' + (plotOffset.left + plotWidth + options.grid.labelMargin) +'px;width:' + axis.labelWidth + 'px;text-align:left" class="tickLabel">' + tick.label + "</div>";
            });

            html += '</div>';
            
            target.append(html);
        }

        function drawSeries(series) {
            if (series.lines.show || (!series.bars.show && !series.points.show))
                drawSeriesLines(series);
            if (series.bars.show)
                drawSeriesBars(series);
            if (series.points.show)
                drawSeriesPoints(series);
        }
        
        function drawSeriesLines(series) {
            function plotLine(data, offset, axisx, axisy) {
                var prev, cur = null, drawx = null, drawy = null;
                
                ctx.beginPath();
                for (var i = 0; i < data.length; ++i) {
                    prev = cur;
                    cur = data[i];

                    if (prev == null || cur == null)
                        continue;
                    
                    var x1 = prev[0], y1 = prev[1],
                        x2 = cur[0], y2 = cur[1];

                    // clip with ymin
                    if (y1 <= y2 && y1 < axisy.min) {
                        if (y2 < axisy.min)
                            continue;   // line segment is outside
                        // compute new intersection point
                        x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
                        y1 = axisy.min;
                    }
                    else if (y2 <= y1 && y2 < axisy.min) {
                        if (y1 < axisy.min)
                            continue;
                        x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
                        y2 = axisy.min;
                    }

                    // clip with ymax
                    if (y1 >= y2 && y1 > axisy.max) {
                        if (y2 > axisy.max)
                            continue;
                        x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
                        y1 = axisy.max;
                    }
                    else if (y2 >= y1 && y2 > axisy.max) {
                        if (y1 > axisy.max)
                            continue;
                        x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
                        y2 = axisy.max;
                    }

                    // clip with xmin
                    if (x1 <= x2 && x1 < axisx.min) {
                        if (x2 < axisx.min)
                            continue;
                        y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
                        x1 = axisx.min;
                    }
                    else if (x2 <= x1 && x2 < axisx.min) {
                        if (x1 < axisx.min)
                            continue;
                        y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
                        x2 = axisx.min;
                    }

                    // clip with xmax
                    if (x1 >= x2 && x1 > axisx.max) {
                        if (x2 > axisx.max)
                            continue;
                        y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
                        x1 = axisx.max;
                    }
                    else if (x2 >= x1 && x2 > axisx.max) {
                        if (x1 > axisx.max)
                            continue;
                        y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
                        x2 = axisx.max;
                    }

                    if (drawx != axisx.p2c(x1) || drawy != axisy.p2c(y1) + offset)
                        ctx.moveTo(axisx.p2c(x1), axisy.p2c(y1) + offset);
                    
                    drawx = axisx.p2c(x2);
                    drawy = axisy.p2c(y2) + offset;
                    ctx.lineTo(drawx, drawy);
                }
                ctx.stroke();
            }

            function plotLineArea(data, axisx, axisy) {
                var prev, cur = null;
                
                var bottom = Math.min(Math.max(0, axisy.min), axisy.max);
                var top, lastX = 0;

                var areaOpen = false;
                
                for (var i = 0; i < data.length; ++i) {
                    prev = cur;
                    cur = data[i];

                    if (areaOpen && prev != null && cur == null) {
                        // close area
                        ctx.lineTo(axisx.p2c(lastX), axisy.p2c(bottom));
                        ctx.fill();
                        areaOpen = false;
                        continue;
                    }

                    if (prev == null || cur == null)
                        continue;
                        
                    var x1 = prev[0], y1 = prev[1],
                        x2 = cur[0], y2 = cur[1];

                    // clip x values
                    
                    // clip with xmin
                    if (x1 <= x2 && x1 < axisx.min) {
                        if (x2 < axisx.min)
                            continue;
                        y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
                        x1 = axisx.min;
                    }
                    else if (x2 <= x1 && x2 < axisx.min) {
                        if (x1 < axisx.min)
                            continue;
                        y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
                        x2 = axisx.min;
                    }

                    // clip with xmax
                    if (x1 >= x2 && x1 > axisx.max) {
                        if (x2 > axisx.max)
                            continue;
                        y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
                        x1 = axisx.max;
                    }
                    else if (x2 >= x1 && x2 > axisx.max) {
                        if (x1 > axisx.max)
                            continue;
                        y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
                        x2 = axisx.max;
                    }

                    if (!areaOpen) {
                        // open area
                        ctx.beginPath();
                        ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom));
                        areaOpen = true;
                    }
                    
                    // now first check the case where both is outside
                    if (y1 >= axisy.max && y2 >= axisy.max) {
                        ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max));
                        ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max));
                        continue;
                    }
                    else if (y1 <= axisy.min && y2 <= axisy.min) {
                        ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min));
                        ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min));
                        continue;
                    }
                    
                    // else it's a bit more complicated, there might
                    // be two rectangles and two triangles we need to fill
                    // in; to find these keep track of the current x values
                    var x1old = x1, x2old = x2;

                    // and clip the y values, without shortcutting
                    
                    // clip with ymin
                    if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) {
                        x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
                        y1 = axisy.min;
                    }
                    else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) {
                        x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
                        y2 = axisy.min;
                    }

                    // clip with ymax
                    if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) {
                        x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
                        y1 = axisy.max;
                    }
                    else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) {
                        x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
                        y2 = axisy.max;
                    }


                    // if the x value was changed we got a rectangle
                    // to fill
                    if (x1 != x1old) {
                        if (y1 <= axisy.min)
                            top = axisy.min;
                        else
                            top = axisy.max;
                        
                        ctx.lineTo(axisx.p2c(x1old), axisy.p2c(top));
                        ctx.lineTo(axisx.p2c(x1), axisy.p2c(top));
                    }
                    
                    // fill the triangles
                    ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1));
                    ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));

                    // fill the other rectangle if it's there
                    if (x2 != x2old) {
                        if (y2 <= axisy.min)
                            top = axisy.min;
                        else
                            top = axisy.max;
                        
                        ctx.lineTo(axisx.p2c(x2old), axisy.p2c(top));
                        ctx.lineTo(axisx.p2c(x2), axisy.p2c(top));
                    }

                    lastX = Math.max(x2, x2old);
                }

                if (areaOpen) {
                    ctx.lineTo(axisx.p2c(lastX), axisy.p2c(bottom));
                    ctx.fill();
                }
            }
            
            ctx.save();
            ctx.translate(plotOffset.left, plotOffset.top);
            ctx.lineJoin = "round";

            var lw = series.lines.lineWidth;
            var sw = series.shadowSize;
            // FIXME: consider another form of shadow when filling is turned on
            if (sw > 0) {
                // draw shadow in two steps
                ctx.lineWidth = sw / 2;
                ctx.strokeStyle = "rgba(0,0,0,0.1)";
                plotLine(series.data, lw/2 + sw/2 + ctx.lineWidth/2, series.xaxis, series.yaxis);

                ctx.lineWidth = sw / 2;
                ctx.strokeStyle = "rgba(0,0,0,0.2)";
                plotLine(series.data, lw/2 + ctx.lineWidth/2, series.xaxis, series.yaxis);
            }

            ctx.lineWidth = lw;
            ctx.strokeStyle = series.color;
            setFillStyle(series.lines, series.color);
            if (series.lines.fill)
                plotLineArea(series.data, series.xaxis, series.yaxis);
            plotLine(series.data, 0, series.xaxis, series.yaxis);
            ctx.restore();
        }

        function drawSeriesPoints(series) {
            function plotPoints(data, radius, fill, axisx, axisy) {
                for (var i = 0; i < data.length; ++i) {
                    if (data[i] == null)
                        continue;
                    
                    var x = data[i][0], y = data[i][1];
                    if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
                        continue;
                    
                    ctx.beginPath();
                    ctx.arc(axisx.p2c(x), axisy.p2c(y), radius, 0, 2 * Math.PI, true);
                    if (fill)
                        ctx.fill();
                    ctx.stroke();
                }
            }

            function plotPointShadows(data, offset, radius, axisx, axisy) {
                for (var i = 0; i < data.length; ++i) {
                    if (data[i] == null)
                        continue;
                    
                    var x = data[i][0], y = data[i][1];
                    if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
                        continue;
                    ctx.beginPath();
                    ctx.arc(axisx.p2c(x), axisy.p2c(y) + offset, radius, 0, Math.PI, false);
                    ctx.stroke();
                }
            }
            
            ctx.save();
            ctx.translate(plotOffset.left, plotOffset.top);

            var lw = series.lines.lineWidth;
            var sw = series.shadowSize;
            if (sw > 0) {
                // draw shadow in two steps
                ctx.lineWidth = sw / 2;
                ctx.strokeStyle = "rgba(0,0,0,0.1)";
                plotPointShadows(series.data, sw/2 + ctx.lineWidth/2,
                                 series.points.radius, series.xaxis, series.yaxis);

                ctx.lineWidth = sw / 2;
                ctx.strokeStyle = "rgba(0,0,0,0.2)";
                plotPointShadows(series.data, ctx.lineWidth/2,
                                 series.points.radius, series.xaxis, series.yaxis);
            }

            ctx.lineWidth = series.points.lineWidth;
            ctx.strokeStyle = series.color;
            setFillStyle(series.points, series.color);
            plotPoints(series.data, series.points.radius, series.points.fill,
                       series.xaxis, series.yaxis);
            ctx.restore();
        }

        function drawBar(x, y, barLeft, barRight, offset, fill, axisx, axisy, c) {
            var drawLeft = true, drawRight = true,
                drawTop = true, drawBottom = false,
                left = x + barLeft, right = x + barRight,
                bottom = 0, top = y;

            // account for negative bars
            if (top < bottom) {
                top = 0;
                bottom = y;
                drawBottom = true;
                drawTop = false;
            }
            
            // clip
            if (right < axisx.min || left > axisx.max ||
                top < axisy.min || bottom > axisy.max)
                return;
            
            if (left < axisx.min) {
                left = axisx.min;
                drawLeft = false;
            }

            if (right > axisx.max) {
                right = axisx.max;
                drawRight = false;
            }

            if (bottom < axisy.min) {
                bottom = axisy.min;
                drawBottom = false;
            }
            
            if (top > axisy.max) {
                top = axisy.max;
                drawTop = false;
            }

            // fill the bar
            if (fill) {
                c.beginPath();
                c.moveTo(axisx.p2c(left), axisy.p2c(bottom) + offset);
                c.lineTo(axisx.p2c(left), axisy.p2c(top) + offset);
                c.lineTo(axisx.p2c(right), axisy.p2c(top) + offset);
                c.lineTo(axisx.p2c(right), axisy.p2c(bottom) + offset);
                c.fill();
            }

            // draw outline
            if (drawLeft || drawRight || drawTop || drawBottom) {
                c.beginPath();
                left = axisx.p2c(left);
                bottom = axisy.p2c(bottom);
                right = axisx.p2c(right);
                top = axisy.p2c(top);
                
                c.moveTo(left, bottom + offset);
                if (drawLeft)
                    c.lineTo(left, top + offset);
                else
                    c.moveTo(left, top + offset);
                if (drawTop)
                    c.lineTo(right, top + offset);
                else
                    c.moveTo(right, top + offset);
                if (drawRight)
                    c.lineTo(right, bottom + offset);
                else
                    c.moveTo(right, bottom + offset);
                if (drawBottom)
                    c.lineTo(left, bottom + offset);
                else
                    c.moveTo(left, bottom + offset);
                c.stroke();
            }
        }
        
        function drawSeriesBars(series) {
            function plotBars(data, barLeft, barRight, offset, fill, axisx, axisy) {
                for (var i = 0; i < data.length; i++) {
                    if (data[i] == null)
                        continue;
                    drawBar(data[i][0], data[i][1], barLeft, barRight, offset, fill, axisx, axisy, ctx);
                }
            }

            ctx.save();
            ctx.translate(plotOffset.left, plotOffset.top);
            ctx.lineJoin = "round";

            // FIXME: figure out a way to add shadows
            /*
            var bw = series.bars.barWidth;
            var lw = series.bars.lineWidth;
            var sw = series.shadowSize;
            if (sw > 0) {
                // draw shadow in two steps
                ctx.lineWidth = sw / 2;
                ctx.strokeStyle = "rgba(0,0,0,0.1)";
                plotBars(series.data, bw, lw/2 + sw/2 + ctx.lineWidth/2, false);

                ctx.lineWidth = sw / 2;
                ctx.strokeStyle = "rgba(0,0,0,0.2)";
                plotBars(series.data, bw, lw/2 + ctx.lineWidth/2, false);
            }*/

            ctx.lineWidth = series.bars.lineWidth;
            ctx.strokeStyle = series.color;
            setFillStyle(series.bars, series.color);
            var barLeft = series.bars.align == "left" ? 0 : -series.bars.barWidth/2;
            plotBars(series.data, barLeft, barLeft + series.bars.barWidth, 0, series.bars.fill, series.xaxis, series.yaxis);
            ctx.restore();
        }

        function setFillStyle(obj, seriesColor) {
            var fill = obj.fill;
            if (!fill)
                return;
            
            if (obj.fillColor)
                ctx.fillStyle = obj.fillColor;
            else {
                var c = parseColor(seriesColor);
                c.a = typeof fill == "number" ? fill : 0.4;
                c.normalize();
                ctx.fillStyle = c.toString();
            }
        }
        
        function insertLegend() {
            target.find(".legend").remove();

            if (!options.legend.show)
                return;
            
            var fragments = [];
            var rowStarted = false;
            for (i = 0; i < series.length; ++i) {
                if (!series[i].label)
                    continue;
                
                if (i % options.legend.noColumns == 0) {
                    if (rowStarted)
                        fragments.push('</tr>');
                    fragments.push('<tr>');
                    rowStarted = true;
                }

                var label = series[i].label;
                if (options.legend.labelFormatter != null)
                    label = options.legend.labelFormatter(label);
                
                fragments.push(
                    '<td class="legendColorBox"><div style="border:1px solid ' + options.legend.labelBoxBorderColor + ';padding:1px"><div style="width:14px;height:10px;background-color:' + series[i].color + ';overflow:hidden"></div></div></td>' +
                    '<td class="legendLabel">' + label + '</td>');
            }
            if (rowStarted)
                fragments.push('</tr>');
            
            if (fragments.length == 0)
                return;

            var table = '<table style="font-size:smaller;color:' + options.grid.color + '">' + fragments.join("") + '</table>';
            if (options.legend.container != null)
                options.legend.container.html(table);
            else {
                var pos = "";
                var p = options.legend.position, m = options.legend.margin;
                if (p.charAt(0) == "n")
                    pos += 'top:' + (m + plotOffset.top) + 'px;';
                else if (p.charAt(0) == "s")
                    pos += 'bottom:' + (m + plotOffset.bottom) + 'px;';
                if (p.charAt(1) == "e")
                    pos += 'right:' + (m + plotOffset.right) + 'px;';
                else if (p.charAt(1) == "w")
                    pos += 'left:' + (m + plotOffset.left) + 'px;';
                var legend = $('<div class="legend">' + table.replace('style="', 'style="position:absolute;' + pos +';') + '</div>').appendTo(target);
                if (options.legend.backgroundOpacity != 0.0) {
                    // put in the transparent background
                    // separately to avoid blended labels and
                    // label boxes
                    var c = options.legend.backgroundColor;
                    if (c == null) {
                        var tmp;
                        if (options.grid.backgroundColor)
                            tmp = options.grid.backgroundColor;
                        else
                            tmp = extractColor(legend);
                        c = parseColor(tmp).adjust(null, null, null, 1).toString();
                    }
                    var div = legend.children();
                    $('<div style="position:absolute;width:' + div.width() + 'px;height:' + div.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').prependTo(legend).css('opacity', options.legend.backgroundOpacity);
                    
                }
            }
        }


        // interactive features
        
        var lastMousePos = { pageX: null, pageY: null },
            selection = {
                first: { x: -1, y: -1}, second: { x: -1, y: -1},
                show: false, active: false },
            highlights = [],
            clickIsMouseUp = false,
            redrawTimeout = null,
            hoverTimeout = null;
        
        // Returns the data item the mouse is over, or null if none is found
        function findNearbyItem(mouseX, mouseY) {
            var maxDistance = options.grid.mouseActiveRadius,
                lowestDistance = maxDistance * maxDistance + 1,
                item = null, foundPoint = false;

            function result(i, j) {
                return { datapoint: series[i].data[j],
                         dataIndex: j,
                         series: series[i],
                         seriesIndex: i };
            }
            
            for (var i = 0; i < series.length; ++i) {
                var data = series[i].data,
                    axisx = series[i].xaxis,
                    axisy = series[i].yaxis,
                
                    // precompute some stuff to make the loop faster
                    mx = axisx.c2p(mouseX),
                    my = axisy.c2p(mouseY),
                    maxx = maxDistance / axisx.scale,
                    maxy = maxDistance / axisy.scale,
                    checkbar = series[i].bars.show,
                    checkpoint = !(series[i].bars.show && !(series[i].lines.show || series[i].points.show)),
                    barLeft = series[i].bars.align == "left" ? 0 : -series[i].bars.barWidth/2,
                    barRight = barLeft + series[i].bars.barWidth;
                for (var j = 0; j < data.length; ++j) {
                    if (data[j] == null)
                        continue;

                    var x = data[j][0], y = data[j][1];
  
                    if (checkbar) {
                        // For a bar graph, the cursor must be inside the bar
                        // and no other point can be nearby
                        if (!foundPoint && mx >= x + barLeft &&
                            mx <= x + barRight &&
                            my >= Math.min(0, y) && my <= Math.max(0, y))
                            item = result(i, j);
                    }
 
                    if (checkpoint) {
                        // For points and lines, the cursor must be within a
                        // certain distance to the data point
 
                        // check bounding box first
                        if ((x - mx > maxx || x - mx < -maxx) ||
                            (y - my > maxy || y - my < -maxy))
                            continue;

                        // We have to calculate distances in pixels, not in
                        // data units, because the scale of the axes may be different
                        var dx = Math.abs(axisx.p2c(x) - mouseX),
                            dy = Math.abs(axisy.p2c(y) - mouseY),
                            dist = dx * dx + dy * dy;
                        if (dist < lowestDistance) {
                            lowestDistance = dist;
                            foundPoint = true;
                            item = result(i, j);
                        }
                    }
                }
            }

            return item;
        }

        function onMouseMove(ev) {
            // FIXME: temp. work-around until jQuery bug 1871 is fixed
            var e = ev || window.event;
            if (e.pageX == null && e.clientX != null) {
                var de = document.documentElement, b = document.body;
                lastMousePos.pageX = e.clientX + (de && de.scrollLeft || b.scrollLeft || 0);
                lastMousePos.pageY = e.clientY + (de && de.scrollTop || b.scrollTop || 0);
            }
            else {
                lastMousePos.pageX = e.pageX;
                lastMousePos.pageY = e.pageY;
            }
            
            if (options.grid.hoverable && !hoverTimeout)
                hoverTimeout = setTimeout(onHover, 100);

            if (selection.active)
                updateSelection(lastMousePos);
        }
        
        function onMouseDown(e) {
            if (e.which != 1)  // only accept left-click
                return;
            
            // cancel out any text selections
            document.body.focus();

            // prevent text selection and drag in old-school browsers
            if (document.onselectstart !== undefined && workarounds.onselectstart == null) {
                workarounds.onselectstart = document.onselectstart;
                document.onselectstart = function () { return false; };
            }
            if (document.ondrag !== undefined && workarounds.ondrag == null) {
                workarounds.ondrag = document.ondrag;
                document.ondrag = function () { return false; };
            }
            
            setSelectionPos(selection.first, e);
                
            lastMousePos.pageX = null;
            selection.active = true;
            $(document).one("mouseup", onSelectionMouseUp);
        }

        function onClick(e) {
            if (clickIsMouseUp) {
                clickIsMouseUp = false;
                return;
            }

            triggerClickHoverEvent("plotclick", e);
        }
        
        function onHover() {
            triggerClickHoverEvent("plothover", lastMousePos);
            hoverTimeout = null;
        }

        // trigger click or hover event (they send the same parameters
        // so we share their code)
        function triggerClickHoverEvent(eventname, event) {
            var offset = eventHolder.offset(),
                pos = { pageX: event.pageX, pageY: event.pageY },
                canvasX = event.pageX - offset.left - plotOffset.left,
                canvasY = event.pageY - offset.top - plotOffset.top;

            if (axes.xaxis.used)
                pos.x = axes.xaxis.c2p(canvasX);
            if (axes.yaxis.used)
                pos.y = axes.yaxis.c2p(canvasY);
            if (axes.x2axis.used)
                pos.x2 = axes.x2axis.c2p(canvasX);
            if (axes.y2axis.used)
                pos.y2 = axes.y2axis.c2p(canvasY);

            var item = findNearbyItem(canvasX, canvasY);

            if (item) {
                // fill in mouse pos for any listeners out there
                item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left);
                item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top);

                    
            }

            if (options.grid.autoHighlight) {
                for (var i = 0; i < highlights.length; ++i) {
                    var h = highlights[i];
                    if (h.auto &&
                        !(item && h.series == item.series && h.point == item.datapoint))
                        unhighlight(h.series, h.point);
                }
                
                if (item)
                    highlight(item.series, item.datapoint, true);
            }
            
            target.trigger(eventname, [ pos, item ]);
        }

        function triggerRedrawOverlay() {
            if (!redrawTimeout)
                redrawTimeout = setTimeout(redrawOverlay, 50);
        }

        function redrawOverlay() {
            redrawTimeout = null;

            // redraw highlights
            octx.save();
            octx.clearRect(0, 0, canvasWidth, canvasHeight);
            octx.translate(plotOffset.left, plotOffset.top);
            
            var i, hi; 
            for (i = 0; i < highlights.length; ++i) {
                hi = highlights[i];

                if (hi.series.bars.show)
                    drawBarHighlight(hi.series, hi.point);
                else
                    drawPointHighlight(hi.series, hi.point);
            }
            octx.restore();

            // redraw selection
            if (selection.show && selectionIsSane()) {
                octx.strokeStyle = parseColor(options.selection.color).scale(null, null, null, 0.8).toString();
                octx.lineWidth = 1;
                ctx.lineJoin = "round";
                octx.fillStyle = parseColor(options.selection.color).scale(null, null, null, 0.4).toString();
                
                var x = Math.min(selection.first.x, selection.second.x),
                    y = Math.min(selection.first.y, selection.second.y),
                    w = Math.abs(selection.second.x - selection.first.x),
                    h = Math.abs(selection.second.y - selection.first.y);
                
                octx.fillRect(x + plotOffset.left, y + plotOffset.top, w, h);
                octx.strokeRect(x + plotOffset.left, y + plotOffset.top, w, h);
            }
        }
        
        function highlight(s, point, auto) {
            if (typeof s == "number")
                s = series[s];

            if (typeof point == "number")
                point = s.data[point];

            var i = indexOfHighlight(s, point);
            if (i == -1) {
                highlights.push({ series: s, point: point, auto: auto });

                triggerRedrawOverlay();
            }
            else if (!auto)
                highlights[i].auto = false;
        }
            
        function unhighlight(s, point) {
            if (typeof s == "number")
                s = series[s];

            if (typeof point == "number")
                point = s.data[point];

            var i = indexOfHighlight(s, point);
            if (i != -1) {
                highlights.splice(i, 1);

                triggerRedrawOverlay();
            }
        }
        
        function indexOfHighlight(s, p) {
            for (var i = 0; i < highlights.length; ++i) {
                var h = highlights[i];
                if (h.series == s && h.point[0] == p[0]
                    && h.point[1] == p[1])
                    return i;
            }
            return -1;
        }
        
        function drawPointHighlight(series, point) {
            var x = point[0], y = point[1],
                axisx = series.xaxis, axisy = series.yaxis;
            
            if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
                return;
            
            var pointRadius = series.points.radius + series.points.lineWidth / 2;
            octx.lineWidth = pointRadius;
            octx.strokeStyle = parseColor(series.color).scale(1, 1, 1, 0.5).toString();
            var radius = 1.5 * pointRadius;
            octx.beginPath();
            octx.arc(axisx.p2c(x), axisy.p2c(y), radius, 0, 2 * Math.PI, true);
            octx.stroke();
        }

        function drawBarHighlight(series, point) {
            octx.lineJoin = "round";
            octx.lineWidth = series.bars.lineWidth;
            octx.strokeStyle = parseColor(series.color).scale(1, 1, 1, 0.5).toString();
            octx.fillStyle = parseColor(series.color).scale(1, 1, 1, 0.5).toString();
            var barLeft = series.bars.align == "left" ? 0 : -series.bars.barWidth/2;
            drawBar(point[0], point[1], barLeft, barLeft + series.bars.barWidth,
                    0, true, series.xaxis, series.yaxis, octx);
        }
        
        function triggerSelectedEvent() {
            var x1 = Math.min(selection.first.x, selection.second.x),
                x2 = Math.max(selection.first.x, selection.second.x),
                y1 = Math.max(selection.first.y, selection.second.y),
                y2 = Math.min(selection.first.y, selection.second.y);

            var r = {};
            if (axes.xaxis.used)
                r.xaxis = { from: axes.xaxis.c2p(x1), to: axes.xaxis.c2p(x2) };
            if (axes.x2axis.used)
                r.x2axis = { from: axes.x2axis.c2p(x1), to: axes.x2axis.c2p(x2) };
            if (axes.yaxis.used)
                r.yaxis = { from: axes.yaxis.c2p(y1), to: axes.yaxis.c2p(y2) };
            if (axes.y2axis.used)
                r.yaxis = { from: axes.y2axis.c2p(y1), to: axes.y2axis.c2p(y2) };
            
            target.trigger("plotselected", [ r ]);

            // backwards-compat stuff, to be removed in future
            if (axes.xaxis.used && axes.yaxis.used)
                target.trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]);
        }
        
        function onSelectionMouseUp(e) {
            // revert drag stuff for old-school browsers
            if (document.onselectstart !== undefined)
                document.onselectstart = workarounds.onselectstart;
            if (document.ondrag !== undefined)
                document.ondrag = workarounds.ondrag;
            
            // no more draggy-dee-drag
            selection.active = false;
            updateSelection(e);
            
            if (selectionIsSane()) {
                triggerSelectedEvent();
                clickIsMouseUp = true;
            }
            
            return false;
        }

        function setSelectionPos(pos, e) {
            var offset = eventHolder.offset();
            if (options.selection.mode == "y") {
                if (pos == selection.first)
                    pos.x = 0;
                else
                    pos.x = plotWidth;
            }
            else {
                pos.x = e.pageX - offset.left - plotOffset.left;
                pos.x = Math.min(Math.max(0, pos.x), plotWidth);
            }

            if (options.selection.mode == "x") {
                if (pos == selection.first)
                    pos.y = 0;
                else
                    pos.y = plotHeight;
            }
            else {
                pos.y = e.pageY - offset.top - plotOffset.top;
                pos.y = Math.min(Math.max(0, pos.y), plotHeight);
            }
        }
        
        function updateSelection(pos) {
            if (pos.pageX == null)
                return;
            
            setSelectionPos(selection.second, pos);
            if (selectionIsSane()) {
                selection.show = true;
                triggerRedrawOverlay();
            }
            else
                clearSelection();
        }

        function clearSelection() {
            if (selection.show) {
                selection.show = false;
                triggerRedrawOverlay();
            }
        }

        function setSelection(ranges, preventEvent) {
            var range;
            
            if (options.selection.mode == "y") {
                selection.first.x = 0;
                selection.second.x = plotWidth;
            }
            else {
                range = extractRange(ranges, "x");
                
                selection.first.x = range.axis.p2c(range.from);
                selection.second.x = range.axis.p2c(range.to);
            }
            
            if (options.selection.mode == "x") {
                selection.first.y = 0;
                selection.second.y = plotHeight;
            }
            else {
                range = extractRange(ranges, "y");
                
                selection.first.y = range.axis.p2c(range.from);
                selection.second.y = range.axis.p2c(range.to);
            }

            selection.show = true;
            triggerRedrawOverlay();
            if (!preventEvent)
                triggerSelectedEvent();
        }
        
        function selectionIsSane() {
            var minSize = 5;
            return Math.abs(selection.second.x - selection.first.x) >= minSize &&
                Math.abs(selection.second.y - selection.first.y) >= minSize;
        }
    }
    
    $.plot = function(target, data, options) {
        var plot = new Plot(target, data, options);
        /*var t0 = new Date();     
        var t1 = new Date();
        var tstr = "time used (msecs): " + (t1.getTime() - t0.getTime())
        if (window.console)
            console.log(tstr);
        else
            alert(tstr);*/
        return plot;
    };
    
    // round to nearby lower multiple of base
    function floorInBase(n, base) {
        return base * Math.floor(n / base);
    }
    
    function clamp(min, value, max) {
        if (value < min)
            return value;
        else if (value > max)
            return max;
        else
            return value;
    }
    
    // color helpers, inspiration from the jquery color animation
    // plugin by John Resig
    function Color (r, g, b, a) {
       
        var rgba = ['r','g','b','a'];
        var x = 4; //rgba.length
       
        while (-1<--x) {
            this[rgba[x]] = arguments[x] || ((x==3) ? 1.0 : 0);
        }
       
        this.toString = function() {
            if (this.a >= 1.0) {
                return "rgb("+[this.r,this.g,this.b].join(",")+")";
            } else {
                return "rgba("+[this.r,this.g,this.b,this.a].join(",")+")";
            }
        };

        this.scale = function(rf, gf, bf, af) {
            x = 4; //rgba.length
            while (-1<--x) {
                if (arguments[x] != null)
                    this[rgba[x]] *= arguments[x];
            }
            return this.normalize();
        };

        this.adjust = function(rd, gd, bd, ad) {
            x = 4; //rgba.length
            while (-1<--x) {
                if (arguments[x] != null)
                    this[rgba[x]] += arguments[x];
            }
            return this.normalize();
        };

        this.clone = function() {
            return new Color(this.r, this.b, this.g, this.a);
        };

        var limit = function(val,minVal,maxVal) {
            return Math.max(Math.min(val, maxVal), minVal);
        };

        this.normalize = function() {
            this.r = limit(parseInt(this.r), 0, 255);
            this.g = limit(parseInt(this.g), 0, 255);
            this.b = limit(parseInt(this.b), 0, 255);
            this.a = limit(this.a, 0, 1);
            return this;
        };

        this.normalize();
    }
    
    var lookupColors = {
        aqua:[0,255,255],
        azure:[240,255,255],
        beige:[245,245,220],
        black:[0,0,0],
        blue:[0,0,255],
        brown:[165,42,42],
        cyan:[0,255,255],
        darkblue:[0,0,139],
        darkcyan:[0,139,139],
        darkgrey:[169,169,169],
        darkgreen:[0,100,0],
        darkkhaki:[189,183,107],
        darkmagenta:[139,0,139],
        darkolivegreen:[85,107,47],
        darkorange:[255,140,0],
        darkorchid:[153,50,204],
        darkred:[139,0,0],
        darksalmon:[233,150,122],
        darkviolet:[148,0,211],
        fuchsia:[255,0,255],
        gold:[255,215,0],
        green:[0,128,0],
        indigo:[75,0,130],
        khaki:[240,230,140],
        lightblue:[173,216,230],
        lightcyan:[224,255,255],
        lightgreen:[144,238,144],
        lightgrey:[211,211,211],
        lightpink:[255,182,193],
        lightyellow:[255,255,224],
        lime:[0,255,0],
        magenta:[255,0,255],
        maroon:[128,0,0],
        navy:[0,0,128],
        olive:[128,128,0],
        orange:[255,165,0],
        pink:[255,192,203],
        purple:[128,0,128],
        violet:[128,0,128],
        red:[255,0,0],
        silver:[192,192,192],
        white:[255,255,255],
        yellow:[255,255,0]
    };    

    function extractColor(element) {
        var color, elem = element;
        do {
            color = elem.css("background-color").toLowerCase();
            // keep going until we find an element that has color, or
            // we hit the body
            if (color != '' && color != 'transparent')
                break;
            elem = elem.parent();
        } while (!$.nodeName(elem.get(0), "body"));

        // catch Safari's way of signalling transparent
        if (color == "rgba(0, 0, 0, 0)") 
            return "transparent";
        
        return color;
    }
    
    // parse string, returns Color
    function parseColor(str) {
        var result;

        // Look for rgb(num,num,num)
        if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))
            return new Color(parseInt(result[1], 10), parseInt(result[2], 10), parseInt(result[3], 10));
        
        // Look for rgba(num,num,num,num)
        if (result = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))
            return new Color(parseInt(result[1], 10), parseInt(result[2], 10), parseInt(result[3], 10), parseFloat(result[4]));
            
        // Look for rgb(num%,num%,num%)
        if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))
            return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55);

        // Look for rgba(num%,num%,num%,num)
        if (result = /rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))
            return new Color(parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55, parseFloat(result[4]));
        
        // Look for #a0b1c2
        if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))
            return new Color(parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16));

        // Look for #fff
        if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))
            return new Color(parseInt(result[1]+result[1], 16), parseInt(result[2]+result[2], 16), parseInt(result[3]+result[3], 16));

        // Otherwise, we're most likely dealing with a named color
        var name = $.trim(str).toLowerCase();
        if (name == "transparent")
            return new Color(255, 255, 255, 0);
        else {
            result = lookupColors[name];
            return new Color(result[0], result[1], result[2]);
        }
    }
        
})(jQuery);

(function($) {
    $.fn.svOfferingStartEndDates = function(options) {
        options = $.extend({
            customValidation: {
                rules: {
                    enddate: {
                        isLaterThanStart: true
                    }
                }
            },
            submitStyle: 'async',
            action: 'EDIT',
            startDateInputName: '',
            endDateInputName: ''
        }, options);

        return new $.svOfferingStartEndDates(this, options);
    };

    $.svOfferingStartEndDates = function(element, options) {

        var start = $('input[name=' + options.startDateInputName + ']');
	    var end = $('input[name=' + options.endDateInputName + ']');
		
		
		
		var setup = function() {
			var start = $('input[name=' + options.startDateInputName + ']');
	        var end = $('input[name=' + options.endDateInputName + ']');
			var isEndDateLaterThanStart = function() {
				var startdate = new Date(start.attr('value'));
				var enddate = new Date(end.attr('value'));
				startdate.setHours(0,0,0,0); 
				enddate.setHours(0,0,0,0); 
				if (startdate - enddate != 0) {
					return false;
				}
				else {
					return start.attr('value') < end.attr('value');
				}
			};
			$.validator.addMethod("isLaterThanStart", isEndDateLaterThanStart, "Course Offering must end later on the same day.");
			start.svDatePicker({
					afterClose: function(){
						if (end.attr('value') == '' || end.attr('value')  < start.attr('value') ){
								end.attr('value', start.attr('value'));
						}
					}
			});
			end.svDatePicker({});
			$('input.room', '#' + $(element).attr('id') + '-edit').svRoomAutocomplete();
		};
		
			
		var trainingcourseofferingheader = $('#trainingcourseofferingheader').svEditableSection({
			customValidation: options.customValidation,
			onSuccess: setup,
			submitStyle: options.submitStyle,
            action: options.action
		});

        setup(element, start, end);

    };

})(jQuery);
