var Class = {
	create: function() {
		return function() {
			this.initialize.apply(this, arguments);
		}
	}
};
Object.extend = function(destination, source) {
	for (var property in source) destination[property] = source[property];
	return destination;
};
Function.prototype.bind = function(object) {
	var __method = this;
	return function() {
		return __method.apply(object, arguments);
	}
};
if (!Array.prototype.forEach){
	Array.prototype.forEach = function(fn, bind){
		for(var i = 0; i < this.length ; i++) fn.call(bind, this[i], i);
	};
}
Array.prototype.each = Array.prototype.forEach;

var $A = function(iterable) {
	var nArray = [];
	for (var i = 0; i < iterable.length; i++) nArray.push(iterable[i]);
	return nArray;
};
function $() {
	if (arguments.length == 1) return get$(arguments[0]);
	var elements = [];
	$c(arguments).each(function(el){
		elements.push(get$(el));
	});
	return elements;
	function get$(el){
		if (typeof el == 'string') el = document.getElementById(el);
		return el;
	}
};
var Info = {
  Browser: {
    IE:     !!(window.attachEvent && !window.opera),
    Opera:  !!window.opera,
    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
    MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
  },
  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>'
};
Object.extend(Object,{
  isElement: function(object) {
    return object && object.nodeType == 1;
  },
  isArray: function(object) {
    return object && object.constructor === Array;
  },
  isFunction: function(object) {
    return typeof object == "function";
  },
  isString: function(object) {
    return typeof object == "string";
  },
  isNumber: function(object) {
    return typeof object == "number";
  },
  isUndefined: function(object) {
    return typeof object == "undefined";
  }	  
});
RegExp.prototype.match = RegExp.prototype.test;
RegExp.escape = function(str) {
  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};
Object.extend(String, {
  interpret: function(value) {
    return value == null ? '' : String(value);
  },
  specialChar: {
    '\b': '\\b',
    '\t': '\\t',
    '\n': '\\n',
    '\f': '\\f',
    '\r': '\\r',
    '\\': '\\\\'
  }
});
Object.extend(String.prototype, {
  truncate: function(length, truncation) {
    length = length || 30;
    truncation = Object.isUndefined(truncation) ? '...' : truncation;
    return this.length > length ?
      this.slice(0, length - truncation.length) + truncation : String(this);
  },
  strip: function() {
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
  },
  stripTags: function() {
    return this.replace(/<\/?[^>]+>/gi, '');
  },
  stripScripts: function() {
    return this.replace(new RegExp(Info.ScriptFragment, 'img'), '');
  },
  toArray: function() {
    return this.split('');
  },
  succ: function() {
    return this.slice(0, this.length - 1) +
      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
  },
  times: function(count) {
    return count < 1 ? '' : new Array(count + 1).join(this);
  },
  camelize: function() {
    var parts = this.split('-'), len = parts.length;
    if (len == 1) return parts[0];
    var camelized = this.charAt(0) == '-'
      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
      : parts[0];
    for (var i = 1; i < len; i++)
      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
    return camelized;
  },
  capitalize: function() {
    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
  },
  include: function(pattern) {
    return this.indexOf(pattern) > -1;
  },
  startsWith: function(pattern) {
    return this.indexOf(pattern) === 0;
  },
  endsWith: function(pattern) {
    var d = this.length - pattern.length;
    return d >= 0 && this.lastIndexOf(pattern) === d;
  },
  blank: function() {
    return /^\s*$/.test(this);
  },
  empty: function() {
    return this == '';
  }
});
if (!window.Element) var Element = {};

Object.extend(Element, {
	visible: function(element) {
		return $(element).style.display != 'none';
  	},
  	toggle: function(element) {
		element = $(element);
		Element[Element.visible(element) ? 'hide' : 'show'](element);
		return element;
  	},
  	hide: function(element) {
		$(element).style.display = 'none';
		return element;
  	},
  	show: function(element) {
		$(element).style.display = '';
		return element;
  	},
	remove: function(element) {
		element = $(element);
		element.parentNode.removeChild(element);
	},
	hasClassName: function(element, className) {
		element = $(element);
		return !!element.className.match(new RegExp("\\b"+className+"\\b"));
	},
	addClassName: function(element, className) {
		element = $(element);
		if (!Element.hasClassName(element, className)) element.className = (element.className+' '+className);
	},
	removeClassName: function(element, className) {
		element = $(element);
		if (Element.hasClassName(element, className)) element.className = element.className.replace(className, '');
	},
	setOpacity: function(element, value) {
    	element = $(element);
		element.style.opacity = (value == 1 || value === '') ? '' :
      		(value < 0.00001) ? 0 : value;
    	return element;
  	},
  	getHeight: function(element) {
    	return this.dimensions(element).height;
  	},
  	getWidth: function(element) {
    	return this.dimensions(element).width;
  	},
  	getTop: function(element) {
    	return this.position(element).top;
  	},
  	getLeft: function(element) {
    	return this.position(element).left;
  	},
  	getRight: function(element) {
    	element = $(element);
		var posL = this.position(element).left;
		var eleW = this.dimensions(element).width;
		var result = posL+eleW;
		return result;
  	},
  	getBottom: function(element) {
    	element = $(element);
		var posT = this.position(element).top;
		var eleH = this.dimensions(element).height;
		var result = posT+eleH;
		return result;
  	},
  	dimensions: function(element) {
    	element = $(element);
    	var display = $(element).style.display;
    	if (display != 'none' && display != null)
      		return {width: element.offsetWidth, height: element.offsetHeight};
			var els = element.style;
			var originalVisibility = els.visibility;
			var originalPosition = els.position;
			var originalDisplay = els.display;
				els.visibility = 'hidden';
				els.position = 'absolute';
				els.display = 'block';
			var originalWidth = element.clientWidth;
			var originalHeight = element.clientHeight;
				els.display = originalDisplay;
				els.position = originalPosition;
				els.visibility = originalVisibility;
			return {width: originalWidth, height: originalHeight};
	},
	position: function(element) {
		element = $(element);
		var valueT = 0, valueL = 0;
		do {
		  valueT += element.offsetTop  || 0;
		  valueL += element.offsetLeft || 0;
		  element = element.offsetParent;
		  if (element) {
			if (element.tagName == 'BODY') break;
			var p = element.style.position;
			if (p == 'relative' || p == 'absolute') break;
		  }
		} while (element);
			return Element._returnOffset(valueL, valueT);
  	}
});
Element._returnOffset = function(l, t) {
  var result = [l, t];
  result.left = l;
  result.top = t;
  return result;
};

document.getElementsByClassName = function(className){
	var elements = [];
	var all = document.getElementsByTagName('*');
	$A(all).each(function(el){
		if (Element.hasClassName(el, className)) elements.push(el);
	});
	return elements;
};

Ajax = Class.create();
Ajax.prototype = {
	initialize: function(url, options){
		this.transport = this.getTransport();
		this.parameters = options.parameters || '';
		this.method = options.method || 'post';
		this.onComplete = options.onComplete || null;
		this.update = $(options.update) || null;
		this.request(url);
	},
	request: function(url){
		this.transport.open(this.method, url, true);
		this.transport.onreadystatechange = this.onStateChange.bind(this);
		if (this.method == 'post') {
			this.transport.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
			if (this.transport.overrideMimeType) this.transport.setRequestHeader('Connection', 'close');
		}
		this.transport.send(this.parameters);
	},
	onStateChange: function(){
		if (this.transport.readyState == 4 && this.transport.status == 200) {
			if (this.onComplete) 
				setTimeout(function(){this.onComplete(this.transport);}.bind(this), 10);
			if (this.update)
				setTimeout(function(){this.update.innerHTML = this.transport.responseText;}.bind(this), 10);
			this.transport.onreadystatechange = function(){};
		}
	},
	getTransport: function() {
		if (window.ActiveXObject) return new ActiveXObject('Microsoft.XMLHTTP');
		else if (window.XMLHttpRequest) return new XMLHttpRequest();
		else return false;
	}
};

var Form = {
  serialize: function(form) {
    var elements = Form.getElements($(form));
    var queryComponents = new Array();
    
    for (var i = 0; i < elements.length; i++) {
      var queryComponent = Form.Element.serialize(elements[i]);
      if (queryComponent)
        queryComponents.push(queryComponent);
    }
    return queryComponents.join('&');
  },
  getElements: function(form) {
    form = $(form);
    var elements = new Array();
    for (tagName in Form.Element.Serializers) {
      var tagElements = form.getElementsByTagName(tagName);
      for (var j = 0; j < tagElements.length; j++)
        elements.push(tagElements[j]);
    }
    return elements;
  },
  getInputs: function(form, typeName, name) {
    form = $(form);
    var inputs = form.getElementsByTagName('input');
    if (!typeName && !name)
      return inputs;
    var matchingInputs = new Array();
    for (var i = 0; i < inputs.length; i++) {
      var input = inputs[i];
      if ((typeName && input.type != typeName) ||
          (name && input.name != name)) 
        continue;
      matchingInputs.push(input);
    }
    return matchingInputs;
  },
  disable: function(form) {
    var elements = Form.getElements(form);
    for (var i = 0; i < elements.length; i++) {
      var element = elements[i];
      element.blur();
      element.disabled = 'true';
    }
  },
  enable: function(form) {
    var elements = Form.getElements(form);
    for (var i = 0; i < elements.length; i++) {
      var element = elements[i];
      element.disabled = '';
    }
  },
  findFirstElement: function(form) {
    return Form.getElements(form).find(function(element) {
      return element.type != 'hidden' && !element.disabled &&
        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
    });
  },
  focusFirstElement: function(form) {
    Field.activate(Form.findFirstElement(form));
  },
  reset: function(form) {
    $(form).reset();
  }
}
Form.Element = {
  serialize: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    var parameter = Form.Element.Serializers[method](element);
    if (parameter) {
      var key = encodeURIComponent(parameter[0]);
      if (key.length == 0) return;  
      if (parameter[1].constructor != Array)
        parameter[1] = [parameter[1]];
      var value = encodeURIComponent(parameter[1]);
      return key + '=' + value;
    }
  },
  getValue: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    var parameter = Form.Element.Serializers[method](element);
    if (parameter)
      return parameter[1];
  }
}
Form.Element.Serializers = {
  input: function(element) {
    switch (element.type.toLowerCase()) {
      case 'submit':
	  case 'image':
      case 'hidden':
      case 'password':
      case 'text':
        return Form.Element.Serializers.textarea(element);
      case 'checkbox':  
      case 'radio':
        return Form.Element.Serializers.inputSelector(element);
    }
    return false;
  },
  inputSelector: function(element) {
    if (element.checked)
      return [element.name, element.value];
  },
  textarea: function(element) {
    return [element.name, element.value];
  },
  select: function(element) {
    return Form.Element.Serializers[element.type == 'select-one' ? 
      'selectOne' : 'selectMany'](element);
  },
  selectOne: function(element) {
    var value = '', opt, index = element.selectedIndex;
    if (index >= 0) {
      opt = element.options[index];
      value = opt.value;
      if (!value && !('value' in opt))
        value = opt.text;
    }
    return [element.name, value];
  },
  selectMany: function(element) {
    var value = new Array();
    for (var i = 0; i < element.length; i++) {
      var opt = element.options[i];
      if (opt.selected) {
        var optValue = opt.value;
        if (!optValue && !('value' in opt))
          optValue = opt.text;
        value.push(optValue);
      }
    }
    return [element.name, value];
  }
}



Selection = function(input){
	this.isTA = (this.input = input).nodeName.toLowerCase() == "textarea";
};
with({o: Selection.prototype}){
	o.setCaret = function(start, end){
		var o = this.input;
		if(Selection.isStandard)
			o.setSelectionRange(start, end);
		else if(Selection.isSupported){
			var t = this.input.createTextRange();
			end -= start + o.value.slice(start + 1, end).split("\n").length - 1;
			start -= o.value.slice(0, start).split("\n").length - 1;
			t.move("character", start), t.moveEnd("character", end), t.select();
		}
	};
	o.getCaret = function(){
		var o = this.input, d = document;
		if(Selection.isStandard)
			return {start: o.selectionStart, end: o.selectionEnd};
		else if(Selection.isSupported){
			var s = (this.input.focus(), d.selection.createRange()), r, start, end, value;
			if(s.parentElement() != o)
				return {start: 0, end: 0};
			if(this.isTA ? (r = s.duplicate()).moveToElementText(o) : r = o.createTextRange(), !this.isTA)
				return r.setEndPoint("EndToStart", s), {start: r.text.length, end: r.text.length + s.text.length};
			for(var $ = "[###]"; (value = o.value).indexOf($) + 1; $ += $);
			r.setEndPoint("StartToEnd", s), r.text = $ + r.text, end = o.value.indexOf($);
			s.text = $, start = o.value.indexOf($);
			if(d.execCommand && d.queryCommandSupported("Undo"))
				for(r = 3; --r; d.execCommand("Undo"));
			return o.value = value, this.setCaret(start, end), {start: start, end: end};
		}
		return {start: 0, end: 0};
	};
	o.getText = function(){
		var o = this.getCaret();
		if(this.input.value.slice(o.start, o.end)==""){
			alert("Please highlight the text you want to apply this style to.");
			return false;
		}else{
			return this.input.value.slice(o.start, o.end);
		}
	};
	o.setText = function(text){
		var o = this.getCaret(), i = this.input, s = i.value;
		i.value = s.slice(0, o.start) + text + s.slice(o.end);
		this.setCaret(o.start += text.length, o.start);
	};
	new function(){
		var d = document, o = d.createElement("input"), s = Selection;
		s.isStandard = "selectionStart" in o;
		s.isSupported = s.isStandard || (o = d.selection) && !!o.createRange();
	};
}