// <script>


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  REMOVE IE6+ BACKGROUND FLICKER 
//		see: http://www.mister-pixel.com/
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	try {
	  document.execCommand("BackgroundImageCache", false, true);
	} catch(err) {}




// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  ELEMENT METHODS
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  getParentByClassName
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	Element.Methods.getParentByClassName = function(element, className) {

		element = $(element);
		
		while ((element.parentNode) && 
		       (element.tagName && element.tagName.toUpperCase() != "BODY") &&
		       (!Element.hasClassName(element, className)) ) {
				element = element.parentNode;
		}
	  
		if (!Element.hasClassName(element, className)) return false;
		    
		return element;	
	};
	Element.getParentByClassName = Element.Methods.getParentByClassName;





	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  getParentByTagName
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	Element.Methods.getParentByTagName = function(element, tagName) {

		element = $(element);
		tagName = tagName.toUpperCase();
		
		while (element!=undefined && element.parentNode && element.tagName && 
		       element.tagName.toUpperCase() != "BODY" && element.tagName.toUpperCase() != tagName) {
				element = element.parentNode;
		}
	  
		if ((element==undefined)|| (!(element.tagName && element.tagName.toUpperCase() == tagName))) return false;
		    
		return element;	
	};
	Element.getParentByTagName = Element.Methods.getParentByTagName;





	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  hideAndDisable
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	Element.Methods.hideAndDisable = function(element) {

		element = $(element);
		
		var fields = element.tagName.match(/input|select|textarea/i) ? [element] : Form.getElements(element);
		fields.each(function(field) {
			field.disabled = true;
			Element.hide(field);						
		});
		
		// don't forget to hide the container!
		Element.hide(element);	
		
	};
	Element.hideAndDisable = Element.Methods.hideAndDisable;



	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  showAndEnable
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	Element.Methods.showAndEnable = function(element) {

		element = $(element);
		
		var fields = element.tagName.match(/input|select|textarea/i) ? [element] : Form.getElements(element);
		fields.each(function(field) {
			field.disabled = field.getAttribute('readonly') ? true : false;
			Element.show(field);						
		});
		
		// don't forget to show the container!
		Element.show(element);	
		
	};
	Element.showAndEnable = Element.Methods.showAndEnable;




	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  addClassNameToFormElements
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	Element.Methods.addClassNameToFormElements = function(element, className) {

		var fields = element.tagName.match(/input|select|textarea/i) ? [element] : Form.getElements(element);
		fields.each(function(field) { Element.addClassName(field, className) });
		
	};
	Element.addClassNameToFormElements = Element.Methods.addClassNameToFormElements;




	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  removeClassNameFromFormElements
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	Element.Methods.removeClassNameFromFormElements = function(element, className) {

		var fields = element.tagName.match(/input|select|textarea/i) ? [element] : Form.getElements(element);
		fields.each(function(field) { Element.removeClassName(field, className) });
		
	};
	Element.removeClassNameFromFormElements = Element.Methods.removeClassNameFromFormElements;




	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  isFieldsetHidden
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	Element.Methods.isFieldsetVisible = function(element) {

		element = $(element);
		
		var fieldset = Element.Methods.getParentByTagName(element,'fieldset');
		if (fieldset){
			return fieldset.visible()
		}
		else{
			return false;
		}
		
			
	};
	Element.isFieldsetVisible = Element.Methods.isFieldsetVisible;
	
	
	

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  isShowing
	//    - recursively checks parent nodes for visibility, rather than
	//      just the element itself.
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	Element.Methods.isShowing = function(element) {
		var parent = element.parentNode;
		while (parent && parent != element) {
			if (parent.visible && !parent.visible()) return false;
			element = parent;
			parent = element.parentNode;
		}
		return true;			
	};
	Element.isShowing = Element.Methods.isShowing;
	
	
	


	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  ** ADD ALL NEW ELEMENT METHODS **
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	Element.addMethods();







// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//  FORM METHODS
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  setReadOnly
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	Form.enableReadOnlyElements = function(form){
		// find any elements with both readonly and disabled properties,
		// and enable the field for form submit
		Form.getElements($(form)).each(function(element){
			if(element.getAttribute('readonly')&&(element.disabled)){
				element.disabled = false;
			}				
		});
	}
	
	Form.disableReadOnlyElements = function(form){
		// find any elements with both readonly property,
		// and disable the field to protect it from user changes
		Form.getElements($(form)).each(function(element){
			if(element.getAttribute('readonly')&&(!element.disabled)){
				element.disabled = true;
			}				
		});
	}
	
	
	
	
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  getCheckedValue
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	Form.getCheckedValue = function(formObj){

		return(formObj.findAll(function(obj){
			return obj.checked;
		}).pluck("value").toString());

	}	

	findFirstElement_v2 = function(form) {
	  return $A(Form.getInputs(form)).find(function(element) {
	    return element.type != 'hidden' && !element.disabled &&
	      ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
	  });
	}

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  serialize - OVERRIDDEN FROM PROTOTYPE to optionally ignore disabled fields
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	Form.serialize = function(form, ignoreDisabled) {
	  var elements = Form.getElements($(form));
	  var queryComponents = new Array();

	  for (var i = 0; i < elements.length; i++) {
				if (!ignoreDisabled || !elements[i].disabled) {
					var queryComponent = Form.Element.serialize(elements[i]);
					if (queryComponent)
					  queryComponents.push(queryComponent);
				}
	  }

	  return queryComponents.join('&');
	}





	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  EventObserver registerCallback - OVERRIDDEN FROM PROTOTYPE to work with radio groups
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  Form.Element.EventObserver.prototype.registerCallback = function(element) {
    if (element.type) {
      switch (element.type.toLowerCase()) {
        case 'checkbox':
          Event.observe(element, 'click', this.onElementEvent.bind(this));
          break;
        case 'radio':
          Form.getInputs(element.form, null, element.name).each( function(e) {
						Event.observe(e, 'click', this.onElementEvent.bind(this));
					}.bind(this));
          break;
        case 'password':
        case 'text':
        case 'textarea':
        case 'select-one':
        case 'select-multiple':
          Event.observe(element, 'change', this.onElementEvent.bind(this));
          break;
      }
    }
  }
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  set a selectbox option using its option value
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	Form.Element.setSelectOptionByValue = function(element,optValue) {
	
		var optIndexToSelect = Form.Element.getOptionIndex(element,optValue);
		if (optIndexToSelect >= 0){
			element.selectedIndex = optIndexToSelect;
		}
	
	}

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  getOptionIndex - obtain index of selectone using option value
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	Form.Element.getOptionIndex = function(element,optValue) {
		return $A(element.options).pluck("value").indexOf(optValue);
	}
	
	
	
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  hideAndDisable
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	Element.Methods.hideAndDisable = function(element) {

		element = $(element);
		
		var fields = element.tagName.match(/input|select|textarea/i) ? [element] : Form.getElements(element);
		fields.each(function(field) {
			field.disabled = true;
			Element.hide(field);						
		});
		
		// don't forget to hide the container!
		Element.hide(element);	
		
		return element;
	};
	Element.hideAndDisable = Element.Methods.hideAndDisable;



	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  showAndEnable
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	Element.Methods.showAndEnable = function(element) {

		element = $(element);
		
		var fields = element.tagName.match(/input|select|textarea/i) ? [element] : Form.getElements(element);
		fields.each(function(field) {
			field.disabled = field.getAttribute('readonly') ? true : false;
			Element.show(field);						
		});
		
		// don't forget to show the container!
		Element.show(element);	
		
		return element;
	};
	Element.showAndEnable = Element.Methods.showAndEnable;	
	
	
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//  Form Behavior
	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	Form.Behavior = new Object();
	
	Form.Behavior.Actions = $H({
	
		"show/hide" : [
			function(element) {
				element.showAndEnable().removeClassNameFromFormElements("dmHidden");
			}, 
			function(element) {
				element.hideAndDisable().addClassNameToFormElements("dmHidden");
			}
		],
		
		"lock/unlock" : [
			function(element) {
				element.disable().addClassName('readonly');
			},
			function(element) {
				if (element.visible()) element.showAndEnable().removeClassName('readonly');
			}
		],
		
		"clear" : function(element) {
			element.clear();
		},
		
		"syncContentsOf" : function(element, trigger) {
			element.innerHTML = ($F(trigger.fields[0]));
		}
		
	});

	Form.Behavior.Manager = {
	
		setup : function(rulesDeclaration) {
			this.defineActionMethods();
			rulesDeclaration(this);
			this.checkAllTriggers();			
		},
	
		allTriggers : $H({}),  // collection of all targets on the page in a hash indexed by the trigger field name
	
		checkTrigger : function(fieldName) {
			if (Form.Behavior.Manager.allTriggers[fieldName])
				Form.Behavior.Manager.allTriggers[fieldName].each( function(target) { target.checkTrigger() });		
		},
		
		checkAllTriggers : function() {
			Form.Behavior.Manager.allTriggers.values().each( function(targets) {
				targets.each( function(t) { t.checkTrigger() });		
			});
		},
		
		defineActionMethods : function() {
			var pair = "", actions = [];
			Form.Behavior.Actions.keys().each( function(a) { 
				if ((pair = a.split("/")).length > 1) {
					Form.Behavior.Actions[pair[0]] = Form.Behavior.Actions[a][0];
					Form.Behavior.Actions[pair[1]] = Form.Behavior.Actions[a][1];
					Form.Behavior.Actions[pair[0]].opposite = Form.Behavior.Actions[pair[1]];
					Form.Behavior.Actions[pair[1]].opposite = Form.Behavior.Actions[pair[0]];
					actions.push(pair[0]);
					actions.push(pair[1]);
				} else {
					actions.push(a);
				}
			});
			
			var methodDefinition = new Template(
				'Form.Behavior.Manager.#{0} = function(elementIds) { return (new Form.Behavior.Target(elementIds, Form.Behavior.Actions.#{0}));	};'
			);
			actions.each( function(a) { eval(methodDefinition.evaluate([a])); });
		}
		
	};
	
	Form.Behavior.Target = Class.create();
	Form.Behavior.Target.prototype = {
	
		initialize : function(elementIds, action) {
			this.elements = elementIds.split(",").collect( function(id) { return $(id) });
			this.elements = this.elements.reject( function(el) { return (el == undefined) });
			this.action = action;
			return this;
		},
		
		when : function(fieldName) {
			return this.trigger = new Form.Behavior.Trigger(this, fieldName);
		},
		
		withValueOf : function(fieldName) {
			return this.trigger = new Form.Behavior.Trigger(this, fieldName, true);
		},
		
		checkTrigger : function() {
			// take action on this dependency's elements based on the value of the trigger
			var action = this.trigger.getTriggeredAction();	
			this.elements.each( function(element) {
				if (typeof action == "function") action(element, this.trigger);
			}.bind(this) );
			
			// if any elements were shown or hidden, see if they contain any triggers for other dependencies
			this.elements.each( function(el) {
				// iterate through all form fields within this element or the element itself if it is a form field
				var fields = el.tagName.match(/input|select|textarea/i) ? [el] : Form.getElements(el);
				fields.each( function(field) {
					Form.Behavior.Manager.checkTrigger(field.name || field.id); 
				});
			});
		}
	
	};
	
	
	Form.Behavior.Trigger = Class.create();
	Form.Behavior.Trigger.prototype = {
	
		initialize : function(target, fieldName, periodic) {
			this.target = target;
			this.periodic = periodic;
			this.fieldName = fieldName;
			this.fields = [];
			this.action = target.action;
			this.needsEventHandlers = false;
			this.findFieldsByFieldName(fieldName);
			this.addToTriggerCollection();

			if (this.needsEventHandlers) this.addEventHandlers();
									
		},
		
		findFieldsByFieldName : function(fieldName) {
			if ($(fieldName) && $(fieldName).form && $(fieldName).id == fieldName) { // the last condition is thanks to IE treating name and id the same
				this.fields.push($(fieldName));
			} else {
				// element could not be found by id, so find by name instead
				$A(document.getElementsByTagName("form")).each( function(form) {
					Form.getInputs(form, null, fieldName).each( function(field) {
						this.fields.push(field);
					}.bind(this));
				}.bind(this));
			}		
		},
		
		addEventHandlers : function() {
			this.fields.each( function(field) {
				if (this.periodic) {
					new Form.Element.Observer(field, 0.2, this.checkTargets.bind(this));
				}
				else {
					new Form.Element.EventObserver(field, this.checkTargets.bind(this));
				}
			}.bind(this));
		},
		
		addToTriggerCollection : function() {
			var triggers = Form.Behavior.Manager.allTriggers;
			if (triggers[this.fieldName] == undefined) {
				triggers[this.fieldName] = [];
				this.needsEventHandlers = true;
			}
			triggers[this.fieldName].push(this.target);
		},
		
		is : function(values) {
			return this.setValues(values);
		},
	
		isNot : function(values) {
			this.action = this.action.opposite;
			return this.setValues(values);
		},
		
		setValues : function(values) {
			this.values = (typeof values == "string") ? values.split(",") : values;
			return this; // allows for chaining of triggers using the andWhen method
		},
		
		andWhen : function(fieldName) {
			return this.symbioticTrigger = new Form.Behavior.Trigger(this.target, fieldName, this.action);
		},
		
		checkTargets : function() {
			// check all targets on the page triggered by this field
			Form.Behavior.Manager.checkTrigger(this.fieldName);
		},
		
		getTriggeredAction : function() {
			// determine the action based on comparing the current value of the trigger with the trigger values
			return (this.values && !this.checkValue()) ? this.action.opposite : this.action;
		},
		
		checkValue : function() {
			for (var i=0; i < this.fields.length; i++) {
				var field = this.fields[i];
				var value = field.hasClassName("dmHidden") ? "" : Form.Element.getValue(field);
				if (value == undefined && field.type == "radio") continue;
				if (this.symbioticTrigger) {
					return (this.values.indexOf(value) > -1 && this.symbioticTrigger.checkValue());
				} else {
					return (this.values.indexOf(value) > -1);
				}
			}
		}
	
	};
	
	
