/*jslint browser: true*/

/* MAKE SURE RDC EXISTS WITHOUT OVERWRITING IT */
window.RDC = window.RDC || {};

window.RDC.CONFIG = (function () {
	"use strict";
	function Config() {
		var ua = navigator.userAgent,
	        p = navigator.platform,
	        b = {
	            ie: 0,
	            firefox: 0,
	            safari: 0,
	            chrome: 0,
	            ver: null
	        },
	        s = {
	            win: p.indexOf("Win") === 0,
	            mac: p.indexOf("Mac") === 0,
	            x11: (p.indexOf("X11") === 0 || p.indexOf("Linux") === 0),
	            ipad: ua.indexOf('iPad') > -1,
	            ipod: ua.indexOf('iPod') > -1,
	            iphone: ua.indexOf('iPhone') > -1,
	            n8: ua.indexOf('NokiaN8') > -1,
	            android: ua.indexOf('Android') > -1,
	            tablet: false
	        },
	        isMobile = ua.toLowerCase().indexOf('mobile');
	    s.mobile = (s.iphone || s.ipod || s.n8 || (s.android && isMobile))
	    s.tablet = s.ipad || (s.android && !s.mobile); 

	    if (/AppleWebKit\/(\S+)/.test(ua)) {
	        if (/Chrome\/(\S+)/.test(ua)) {
	            b.ver = RegExp.$1;
	            b.chrome = parseFloat(b.ver);
	        } else if (/Version\/(\S+)/.test(ua)) {
	            b.ver = RegExp.$1;
	            b.safari = parseFloat(b.ver);
	        }
	    } else if (/Firefox\/(\S+)/.test(ua)) {
	        b.ver = RegExp.$1;
	        b.firefox = parseFloat(b.ver);
	    } else if (/MSIE ([0-9\.]+)/.test(ua)) {
			b.ver = RegExp.$1;
	        b.ie = parseFloat(b.ver);
	    }
	    this.BROWSER = b;
	    this.PLATFORM = s;
	}
	Config.prototype = {

		/*RUNTIME MODE*/
		"MODE" : "DEPLOY",

		/*SUPER DOMAIN*/
		"DOMAIN" : "permaconn.com",

		/*UNKNOWN BROWSER REDIRECT*/
		"LEGACY_REDIRECT" : "legacy.php"
	};
	return new Config();
}());

/* NORMALIZE BROWSER DIFFERENCES:
 * THERE IS A THREE TIER SUPPORT EXPECTATION
 * TIER 1: (COMPLETE NATIVE SUPPORT)
 *   1. IE 9+
 *   2. CHROME
 *   3. FIREFOX 4+
 * TIER 2: (SUPPORT THROUGH ES5 PATCH)
 *   1. IE 8
 *   2. FIREFOX 3.6
 *   3. SAFARI (NON-NATIVE BIND)
 *   4. IOS
 *  TIER 3: (NO SUPPORT)
 * 
 */
(function (RDC) {
	"use strict";
	var CONFIG = RDC.CONFIG;
	if (
		(CONFIG.BROWSER.ie > 8) ||
			!!CONFIG.BROWSER.chrome ||
			(CONFIG.BROWSER.firefox > 4)
	) {
		Object.freeze(CONFIG);
	} else if (
		(CONFIG.BROWSER.ie === 8 || document.documentMode === 8) ||
			CONFIG.BROWSER.firefox > 3.5 ||
			CONFIG.BROWSER.safari >= 5 ||
			CONFIG.PLATFORM.mobile ||
			CONFIG.PLATFORM.tablet
	) {
		/*jslint off:true*/

		(function(n){"function"==typeof define?define(n):n()})(function(){function n(a){try{return Object.defineProperty(a,"sentinel",{}),"sentinel"in a}catch(d){}}if(!Function.prototype.bind)Function.prototype.bind=function(a){var d=this;if("function"!=typeof d)throw new TypeError;var b=p.call(arguments,1),c=function(){if(this instanceof c){var e=function(){};e.prototype=d.prototype;var e=new e,g=d.apply(e,b.concat(p.call(arguments)));return null!==g&&Object(g)===g?g:e}return d.apply(a,b.concat(p.call(arguments)))};
			return c};var l=Function.prototype.call,f=Object.prototype,p=Array.prototype.slice,m=l.bind(f.toString),h=l.bind(f.hasOwnProperty),t,u,q,r,o;if(o=h(f,"__defineGetter__"))t=l.bind(f.__defineGetter__),u=l.bind(f.__defineSetter__),q=l.bind(f.__lookupGetter__),r=l.bind(f.__lookupSetter__);if(!Array.isArray)Array.isArray=function(a){return"[object Array]"==m(a)};if(!Array.prototype.forEach)Array.prototype.forEach=function(a,d){var b=i(this),c=0,e=b.length>>>0;if("[object Function]"!=m(a))throw new TypeError;
			for(;c<e;)c in b&&a.call(d,b[c],c,b),c++};if(!Array.prototype.map)Array.prototype.map=function(a,d){var b=i(this),c=b.length>>>0,e=Array(c);if("[object Function]"!=m(a))throw new TypeError;for(var g=0;g<c;g++)g in b&&(e[g]=a.call(d,b[g],g,b));return e};if(!Array.prototype.filter)Array.prototype.filter=function(a,d){var b=i(this),c=b.length>>>0,e=[];if("[object Function]"!=m(a))throw new TypeError;for(var g=0;g<c;g++)g in b&&a.call(d,b[g],g,b)&&e.push(b[g]);return e};if(!Array.prototype.every)Array.prototype.every=
			function(a,d){var b=i(this),c=b.length>>>0;if("[object Function]"!=m(a))throw new TypeError;for(var e=0;e<c;e++)if(e in b&&!a.call(d,b[e],e,b))return!1;return!0};if(!Array.prototype.some)Array.prototype.some=function(a,d){var b=i(this),c=b.length>>>0;if("[object Function]"!=m(a))throw new TypeError;for(var e=0;e<c;e++)if(e in b&&a.call(d,b[e],e,b))return!0;return!1};if(!Array.prototype.reduce)Array.prototype.reduce=function(a){var d=i(this),b=d.length>>>0;if("[object Function]"!=m(a))throw new TypeError;
			if(!b&&1==arguments.length)throw new TypeError;var c=0,e;if(2<=arguments.length)e=arguments[1];else{do{if(c in d){e=d[c++];break}if(++c>=b)throw new TypeError;}while(1)}for(;c<b;c++)c in d&&(e=a.call(void 0,e,d[c],c,d));return e};if(!Array.prototype.reduceRight)Array.prototype.reduceRight=function(a){var d=i(this),b=d.length>>>0;if("[object Function]"!=m(a))throw new TypeError;if(!b&&1==arguments.length)throw new TypeError;var c,b=b-1;if(2<=arguments.length)c=arguments[1];else{do{if(b in d){c=d[b--];
			break}if(0>--b)throw new TypeError;}while(1)}do b in this&&(c=a.call(void 0,c,d[b],b,d));while(b--);return c};if(!Array.prototype.indexOf)Array.prototype.indexOf=function(a){var d=i(this),b=d.length>>>0;if(!b)return-1;var c=0;1<arguments.length&&(c=v(arguments[1]));for(c=0<=c?c:Math.max(0,b+c);c<b;c++)if(c in d&&d[c]===a)return c;return-1};if(!Array.prototype.lastIndexOf)Array.prototype.lastIndexOf=function(a){var d=i(this),b=d.length>>>0;if(!b)return-1;var c=b-1;1<arguments.length&&(c=Math.min(c,
			v(arguments[1])));for(c=0<=c?c:b-Math.abs(c);0<=c;c--)if(c in d&&a===d[c])return c;return-1};if(!Object.getPrototypeOf)Object.getPrototypeOf=function(a){return a.__proto__||(a.constructor?a.constructor.prototype:f)};if(!Object.getOwnPropertyDescriptor)Object.getOwnPropertyDescriptor=function(a,d){if("object"!=typeof a&&"function"!=typeof a||null===a)throw new TypeError("Object.getOwnPropertyDescriptor called on a non-object: "+a);if(h(a,d)){var b,c,e;b={enumerable:!0,configurable:!0};if(o){var g=
			a.__proto__;a.__proto__=f;c=q(a,d);e=r(a,d);a.__proto__=g;if(c||e){if(c)b.get=c;if(e)b.set=e;return b}}b.value=a[d];return b}};if(!Object.getOwnPropertyNames)Object.getOwnPropertyNames=function(a){return Object.keys(a)};if(!Object.create)Object.create=function(a,d){var b;if(null===a)b={__proto__:null};else{if("object"!=typeof a)throw new TypeError("typeof prototype["+typeof a+"] != 'object'");b=function(){};b.prototype=a;b=new b;b.__proto__=a}void 0!==d&&Object.defineProperties(b,d);return b};if(Object.defineProperty){var l=
			n({}),y="undefined"==typeof document||n(document.createElement("div"));if(!l||!y)var s=Object.defineProperty}if(!Object.defineProperty||s)Object.defineProperty=function(a,d,b){if("object"!=typeof a&&"function"!=typeof a||null===a)throw new TypeError("Object.defineProperty called on non-object: "+a);if("object"!=typeof b&&"function"!=typeof b||null===b)throw new TypeError("Property description must be an object: "+b);if(s)try{return s.call(Object,a,d,b)}catch(c){}if(h(b,"value"))if(o&&(q(a,d)||r(a,
			d))){var e=a.__proto__;a.__proto__=f;delete a[d];a[d]=b.value;a.__proto__=e}else a[d]=b.value;else{if(!o)throw new TypeError("getters & setters can not be defined on this javascript engine");h(b,"get")&&t(a,d,b.get);h(b,"set")&&u(a,d,b.set)}return a};if(!Object.defineProperties)Object.defineProperties=function(a,d){for(var b in d)h(d,b)&&Object.defineProperty(a,b,d[b]);return a};if(!Object.seal)Object.seal=function(a){return a};if(!Object.freeze)Object.freeze=function(a){return a};try{Object.freeze(function(){})}catch(D){Object.freeze=
			function(a){return function(d){return"function"==typeof d?d:a(d)}}(Object.freeze)}if(!Object.preventExtensions)Object.preventExtensions=function(a){return a};if(!Object.isSealed)Object.isSealed=function(){return!1};if(!Object.isFrozen)Object.isFrozen=function(){return!1};if(!Object.isExtensible)Object.isExtensible=function(a){if(Object(a)===a)throw new TypeError;for(var d="";h(a,d);)d+="?";a[d]=!0;var b=h(a,d);delete a[d];return b};if(!Object.keys){var w=!0,x="toString,toLocaleString,valueOf,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,constructor".split(","),
			z=x.length,j;for(j in{toString:null})w=!1;Object.keys=function(a){if("object"!=typeof a&&"function"!=typeof a||null===a)throw new TypeError("Object.keys called on a non-object");var d=[],b;for(b in a)h(a,b)&&d.push(b);if(w)for(b=0;b<z;b++){var c=x[b];h(a,c)&&d.push(c)}return d}}if(!Date.prototype.toISOString||-1===(new Date(-621987552E5)).toISOString().indexOf("-000001"))Date.prototype.toISOString=function(){var a,d,b,c;if(!isFinite(this))throw new RangeError;a=[this.getUTCMonth()+1,this.getUTCDate(),
			this.getUTCHours(),this.getUTCMinutes(),this.getUTCSeconds()];c=this.getUTCFullYear();c=(0>c?"-":9999<c?"+":"")+("00000"+Math.abs(c)).slice(0<=c&&9999>=c?-4:-6);for(d=a.length;d--;)b=a[d],10>b&&(a[d]="0"+b);return c+"-"+a.slice(0,2).join("-")+"T"+a.slice(2).join(":")+"."+("000"+this.getUTCMilliseconds()).slice(-3)+"Z"};if(!Date.now)Date.now=function(){return(new Date).getTime()};if(!Date.prototype.toJSON)Date.prototype.toJSON=function(){if("function"!=typeof this.toISOString)throw new TypeError;return this.toISOString()};
			if(!Date.parse||864E13!==Date.parse("+275760-09-13T00:00:00.000Z"))Date=function(a){var d=function g(b,d,c,f,h,i,j){var k=arguments.length;return this instanceof a?(k=1==k&&""+b===b?new a(g.parse(b)):7<=k?new a(b,d,c,f,h,i,j):6<=k?new a(b,d,c,f,h,i):5<=k?new a(b,d,c,f,h):4<=k?new a(b,d,c,f):3<=k?new a(b,d,c):2<=k?new a(b,d):1<=k?new a(b):new a,k.constructor=g,k):a.apply(this,arguments)},b=RegExp("^(\\d{4}|[+-]\\d{6})(?:-(\\d{2})(?:-(\\d{2})(?:T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.(\\d{3}))?)?(?:Z|(?:([-+])(\\d{2}):(\\d{2})))?)?)?)?$"),
			c;for(c in a)d[c]=a[c];d.now=a.now;d.UTC=a.UTC;d.prototype=a.prototype;d.prototype.constructor=d;d.parse=function(d){var c=b.exec(d);if(c){c.shift();for(var f=1;7>f;f++)c[f]=+(c[f]||(3>f?1:0)),1==f&&c[f]--;var h=+c.pop(),i=+c.pop(),j=c.pop(),f=0;if(j){if(23<i||59<h)return NaN;f=6E4*(60*i+h)*("+"==j?-1:1)}h=+c[0];return 0<=h&&99>=h?(c[0]=h+400,a.UTC.apply(this,c)+f-126227808E5):a.UTC.apply(this,c)+f}return a.parse.apply(this,arguments)};return d}(Date);j="\t\n\u000b\u000c\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\ufeff";
			if(!String.prototype.trim||j.trim()){j="["+j+"]";var A=RegExp("^"+j+j+"*"),B=RegExp(j+j+"*$");String.prototype.trim=function(){return(""+this).replace(A,"").replace(B,"")}}var v=function(a){a=+a;a!==a?a=0:0!==a&&a!==1/0&&a!==-(1/0)&&(a=(0<a||-1)*Math.floor(Math.abs(a)));return a},C="a"!="a"[0],i=function(a){if(null==a)throw new TypeError;return C&&"string"==typeof a&&a?a.split(""):Object(a)}});

		/*jslint off:false*/
	} else {
		window.location = 'http://www.' + CONFIG.DOMAIN + '/' + CONFIG.LEGACY_REDIRECT;
	}
}(window.RDC));

if (!('classList' in document.createElement("a"))) {
	Object.defineProperty(Element.prototype, 'classList', {
		"get": (function () {
			function ClassList(elm) {
				var list = elm.className.split(' '),
					listLength = list.length,
					i = 0;
				this.elm = elm;
				while (i < listLength) {
					/* NON EMPTY STRING */
					if (list[i] !== '') {
						this.push(list[i]);
					}
					i += 1;
				}
			}
			function update(self) {
				self.elm.className = self.join(' ');
			}

			ClassList.prototype = [];

			ClassList.prototype.elm = null;

			ClassList.prototype.contains = function contains(className) {
				return this.indexOf(className) !== -1;
			}

			ClassList.prototype.toggle = function contains(className) {
				var contains = this.contains(className);
				this[contains ? 'remove' : 'add' ](className);
				return !contains;
			}

			ClassList.prototype.add = function add(className) {
				if (!this.contains(className)) {
					this.push(className);
					update(this);
				}
			}

			ClassList.prototype.remove = function remove(className) {
				var index = this.indexOf(className);
				if (index !== -1) {
					this.splice(index, 1);
					update(this);
				}
			}
			return function () {return new ClassList(this); }
		}())
	});
}
/*jslint browser: true*/

/* MAKE SURE RDC EXISTS WITHOUT OVERWRITING IT */
window.RDC = window.RDC || {};

/* Class: RDC
 * The RDC singleton is the only global in any RDC application.
 * It mainly interfaces to the back-end of the website through the passing around of classes.
 */
(function (document, RDC) {
	"use strict";
		/* INDEX OF ALL SET CLASSES */
	var modules = {},

		/* INDEX OF CALLBACKS WAITING FOR CLASS TO BE SET */
		moduleListeners = {},

		/* SHORTCUT TO DOCUMENT HEAD */
		head = document.documentElement.firstChild,

		/* SHORT CUT TO CONFIG OBJECT DESCRIBED IN __CONFIG__.JS */
		CONFIG = RDC.CONFIG,

		/* PREFEX TO THE STATIC JS FOLDER ON STATIC SERVER
		 * - THE PROTOCOL IS MATCHED SO THAT WE DONT GET INSECURE MESSAGES, AND SO WE DONT ATTEMPT SECURE OVER INSECURE CONNECTION
		 * - WHEN DEPLOYED ALL CLASSES HAVE BEEN MINIFIED FOR SPEED + SECURITY
		 */
		srcPrefix = window.location.protocol + '//static.' + CONFIG.DOMAIN + '/js/',
		srcSuffix = '.class.min.js';

	/* Function: getClass
	 * *static*
	 * A simple lazy loading API, can load multiple classes at once
	 * 
	 * Errors:
	 * 1 - getClass was called without a string descriptor
	 * 2 - getClass was called without a function callback
	 * 
	 * Parameters:
	 * descriptor - *string|array* The name of the library with an optional version e.g 'form-v1.2' , or an array of strings
	 * callback - *function* The callback to be passed the library
	 * 
	 * Example:
	 * (start code)
	 * //single library use
	 * RDC.getClass('form' , function(Form){...});
	 * //multiple library use
	 * RDC.getClass([
	 *  "form-v1.0",
	 *  "type"
	 * ] , function(Form , Type){...});
	 * (end)
	 * 
	 * Returns:
	 * *undefined*
	 */
	function getClass(descriptor, callback) {
		var script,
			classesRemaining;

		/*MAKE SURE THAT CONFIG EXISTS*/
		CONFIG = CONFIG || RDC.CONFIG;

		/*IF AN ARRAY WAS PROVIDED*/
		if (descriptor instanceof Array) {

			/*THE LENGTH WILL BE DECREMENTED AS A COUNTER OF REMAINING CLASSES TO LOAD*/
			classesRemaining = descriptor.length;

			/*LOOP THROUGH EACH OF THE CLASSES*/
			descriptor.forEach(function (name, index) {

				/*AND RECURSIVLY CALL THIS FUNCTION*/
				getClass(name, function (Constructor) {

					/*PROVIDING AN AUGMENTED CALLBACK*/
					descriptor[index] = Constructor;
					classesRemaining -= 1;
					if (classesRemaining === 0) {
						descriptor.push(CONFIG);
						callback.apply({}, descriptor);
					}
				});
			});
			return;
		}

		/*TYPE CHECKING*/
		if (typeof descriptor !== 'string') {
			throw new Error('RDC::getClass[called without a string descriptor]');
		}
		if (typeof callback !== 'function') {
			throw new Error('RDC::getClass[called without a function callback]');
		}

		/*NOW MAKE IT HAPPEN*/
		if (modules.hasOwnProperty(descriptor)) {/*IF THE MODULE IS ALREADY LOADED*/

			/*CALLBACK DIRECTLY*/
			callback(modules[descriptor], CONFIG);
		} else if (moduleListeners.hasOwnProperty(descriptor)) {/*IF THE MODULE IS LOADING*/

			/*JUST ADD AN EXTRA LISTENER*/
			moduleListeners[descriptor].push(callback);
		} else {/*IF THE MODULE HAS NOT BEEN REQUESTED*/
			moduleListeners[descriptor] = [callback];

			/*FOR SPEED MODIFY BEFORE APPENDED*/
			script = document.createElement('SCRIPT');
			script.src = srcPrefix + descriptor + srcSuffix;

			/*SET TYPE FOR MOZILLA*/
			script.setAttribute('type', 'text/javascript');
			head.appendChild(script);
		}
	}
	RDC.getClass = getClass;

	/* Function: setClass
	 * *static*
	 * After invoking <RDC.getClass>, the RDC object will then add a dynmaic script tag to load up the class.
	 * The dynamic script tag will invoke setClass once ready.
	 * 
	 * Errors:
	 * 1 - The class has already been added
	 * 
	 * Parameters:
	 * name - *string* The name of the library with an optional version e.g 'form-v1.2'.
	 * module - *function* The class itself.
	 * 
	 * Example:
	 * (start code)
	 * //single library use
	 * RDC.setClass('form' , function Form(){...});
	 * (end)
	 * 
	 * Returns:
	 * *undefined*
	 */
	function setClass(name, module) {
		var i = 0;
		if (!modules.hasOwnProperty(name)) {
			/*PLACE A TIMEOUT TO SEPARATE PARSING AND EVENT HANDLERS*/
			modules[name] = module;
			if (moduleListeners.hasOwnProperty(name)) {
				setTimeout(function () {
					do {
						moduleListeners[name][i].call(module, module, CONFIG);
						i += 1;
					} while (i < moduleListeners[name].length);
				}, 20);
			}
		} else {
			throw new Error('RDC::setClass[' + name + ' has already been added]');
		}
	}
	RDC.setClass = setClass;
}(document, window.RDC));/*jslint browser: true*/
/*globals RDC*/
(function () {
	"use strict";

	/* Class: EventEmitter
	 * A standard implementation of the EventEmitter pattern. Has some extra features such as:
	 * 
	 * Bubbling:
	 * (start code)
	 * RDC.getClass('event-emitter' , function(EventEmitter){
	 *  var ev = new EventEmitter();
	 * 
	 *  //generic use
	 *  ev.on('readyStateChange' , function(param1 , param2){
	 *  //this will get called whenever ready state changes
	 *  //gets called 4 times
	 *  console.log('readyStateChange');
	 *  });
	 * 
	 *  //bubble use
	 *  ev.on('readyStateChange:4' ,  function(param1 , param2){
	 *  //this will get called only when ready state changes to four
	 *  console.log('readyStateChange is 4');
	 *  });
	 * 
	 *  ev.emit('readyStateChange:1' , param1 , param2); // 'readyStateChange'
	 *  ev.emit('readyStateChange:2' , param1 , param2); // 'readyStateChange'
	 *  ev.emit('readyStateChange:3' , param1 , param2); // 'readyStateChange'
	 *  ev.emit('readyStateChange:4' , param1 , param2); // 'readyStateChange' 'readyStateChange is 4'
	 * });
	 * (end)
	 * 
	 * Multiple Events:
	 * The above code can be re written like this.
	 * (start code)
	 * RDC.getClass('event-emitter' , function(EventEmitter){
	 *  var ev = new EventEmitter();
	 * 
	 *  ev.on({
	 *  'readyStateChange': function (param1, param2) {
	 *   //this will get called whenever ready state changes
	 *   //gets called 4 times
	 *   console.log('readyStateChange');
	 *  },
	 *  'readyStateChange:4': function (param1, param2) {
	 *   //this will get called only when ready state changes to four
	 *   console.log('readyStateChange is 4');
	 *  }
	 * });
	 *  ev.emit('readyStateChange:1' , param1 , param2); // 'readyStateChange'
	 *  ev.emit('readyStateChange:2' , param1 , param2); // 'readyStateChange'
	 *  ev.emit('readyStateChange:3' , param1 , param2); // 'readyStateChange'
	 *  ev.emit('readyStateChange:4' , param1 , param2); // 'readyStateChange' 'readyStateChange is 4'
	 * });
	 * (end)
	 */

	function EventEmitter() {
		this.eventListeners = {};
	}

	/* Function: morph
	 * *static*
	 * Morph an object into an EventEmitter (instanceof does not work).
	 * This method is a shallow copy of the <EventEmitter>'s methods, nothing more.
	 * 
	 * Parameters:
	 * toEventEmitter - *object* The object that will become an eventEmmitter
	 * 
	 * Errors:
	 * 1 - toEventEmitter is not an object
	 * 
	 * Example:
	 * (start code)
	 * var obj = {}
	 * RDC.getClass('event-emitter' , function(EventEmitter){
	 *  // morph obj into an event-emitter
	 *  EventEmitter.morph(obj);
	 * 
	 *  // subscribe to a custom event
	 *  obj.on('someEvent', function () {
	 *   console.log('some event has been dispacted on obj')
	 *  });
	 * 
	 *  // dispactch the event
	 *  obj.emit('someEvent');
	 * });
	 * (end)
	 */
	EventEmitter.morph = function morph(toEventEmitter) {
		/* MAKE A SHORT CUT */
		var proto = EventEmitter.prototype;

		/* TYPE CHECK */
		if (
			!toEventEmitter ||
				(typeof toEventEmitter !== 'object')
		) {
			throw new Error('EventEmitter::morph[toEventEmitter is not an object]');
		}

		/*
		 * COPY PROPERTIES
		 */
		toEventEmitter.emit = proto.emit;
		toEventEmitter.on = proto.on;
		toEventEmitter.remove = proto.remove;

		/* CREATE */
		EventEmitter.apply(toEventEmitter);
	};

	/* Function: on
	 * *chainable*
	 * Generic event registration method. This is how to bind/attach/listen for an event.
	 * 
	 * Parameters:
	 * eventName - *string*|*object* The name of the event e.g 'focus' or 'readyState:4'
	 * callback - *function* The callback which will be called in the context of the eventEmitter and provided any optional arguments
	 * onceOnly - (optional)*bool* A boolean indicated that the event handler is to be called once only.
	 * 
	 * Errors:
	 * 1 - eventName must be either a string or an object
	 * 2 - callback must be a function
	 * 
	 * Example:
	 * see above <EventEmitter>;
	 */
	EventEmitter.prototype.on = function on(eventName, callback, onceOnly) {
		var i;
		/* STANDARD TYPE CHECKING */
		if (
			!!eventName &&
				(typeof eventName === 'object')
		) {

			/*
			 * IF ITS AN OBJECT
			 * THEN LOOP THROUGH ITS KEYS 
			 * AND SEND EACH VALUE BACK AGAIN
			 */
			for (i in eventName) {
				if (eventName.hasOwnProperty(i)) {
					on.call(this, i, eventName[i], onceOnly);
				}
			}
		} else if (typeof eventName === 'string') {

			/*
			 * IF ITS A STRING THEN
			 * CHECK THAT CALLBACK IS A FUNCTION
			 */
			if (typeof callback === 'function') {
				if (this.eventListeners[eventName] instanceof Array) {

					/* IF THE EVENT HAS BEEN PREVIOUSLY INITIALIZED
					 * PUT THE HANDLER IN AN EXISTING ARRAY
					 */
					this.eventListeners[eventName].push(callback);
				} else {

					/* IF THE EVENT NEVER EXISTED 
					 * INITIALIZE THE ARRAY EVENT EMITTER CONTAINER
					 */
					this.eventListeners[eventName] = [callback];
				}

				this.emit('newListener', eventName, callback);

				/* IF THE ONCE ONLY FLAG IS PASSED
				 * STORE IT ON THE CALLBACK
				 */
				if (onceOnly === true) {
					callback.onceFlag = true;
				} else {
					/* OR ENSURE THAT IT IS NOT THERE */
					delete callback.onceFlag;
				}
			} else {
				throw new Error('EventEmitter::on[callback must be a function]');
			}
		} else {
			throw new Error('EventEmitter::on[eventName must be either a string or an object]');
		}
		return this;
	};

	/* Function: remove
	 * *chainable*
	 * Generic event resignation method
	 * 
	 * Parameters:
	 * eventName - *string* The name of the event e.g 'focus' or 'readyState:4'
	 * callback - *function* The previous event handler passed in
	 * 
	 * (start code)
	 * function foo (){...}
	 * //this is a round about way of calling foo
	 * (new EventEmitter()).on('foo:bar' , foo).emit('foo:bar').remove(foo);
	 * 
	 * (end)
	 * 
	 * Errors:
	 * 1 - eventName must be a string
	 * 2 - callback must be a function
	 */
	EventEmitter.prototype.remove = function remove(eventName, callback) {
		var container = this.eventListeners[eventName],
			i;
		if (typeof eventName !== 'string') {
			throw new Error('EventEmitter::remove[eventName must be a string]');
		}
		if (typeof callback !== 'function') {
			throw new Error('EventEmitter::remove[callback must be a function]');
		}
		/* IF THERE IS AN EVENT CONTAINER */
		if (container instanceof Array) {
			i = container.indexOf(callback);
			/* IF THE CALLBACK IS IN THE CONTAINER */
			if (i !== -1) {
				container.splice(i, 1);
				/* IF SPLICING HAS LEFT THE ARRAY EMPTY */
				if (container.length === 0) {
					delete this.eventListeners[eventName];
				}
			}
		}
		return this;
	};

	/* Function: emit
	 * *chainable*
	 * Generic event trigger method, can pass parameters.
	 * 
	 * Parameters:
	 * type - *string* The name of the event e.g 'focus' or 'readyState:4'
	 * args... - *var* Any variable number of arguments
	 * 
	 * Example:
	 * (start code)
	 *  RDC.getClass('event-emitter', function (EventEmitter) {
	 *  // make the event emitter
	 *  var ev = new EventEmitter();
	 *  
	 *  // bind to a random event
	 *  ev.on('someEvent', function () {
	 *   console.log(arguments);
	 *  });
	 * 
	 *  // dispatch the event
	 *  ev.emit('someEvent', 'a', 'b', 7); // CONSOLE: ['a', 'b', 7]
	 * });
	 * (end)
	 * 
	 * Errors:
	 * 1 - eventName must be a string
	 * 2 - was not called in context
	 */
	EventEmitter.prototype.emit = function emit(eventName) {
		var container,
			applyArgs,
			handler,
			i = 0;

		/*
		 * TYPE CHECK
		 */
		if (typeof eventName !== 'string') {
			throw new Error('EventEmitter::emit[eventName must be a string]');
		}

		/* TO CHECK CONTEXT YOU WOULD THINK THAT INSTANCEOF WOULD WORK
		 * BUT THIS FAILS WHEN MORPH IS USED
		 * SO DUCK-TYPING WILL SUFFICE
		 */
		if (
			!this ||
				!(this.eventListeners instanceof Object)
		) {
			throw new Error('EventEmitter::emit[was not called in context]');
		}

		/* THIS IS SAFE NOW */
		container = this.eventListeners[eventName];

		/*
		 * EMIT THE EVENT IF THERE ARE ANY LISTENERS
		 * FROM THE WAY THAT REMOVE WORKS:
		 * WE KNOW THAT ANY ARRAY WILL HAVE AT LEAST ONE CALLBACK
		 */
		if (container instanceof Array) {
			handler = container[i];
			applyArgs = Array.prototype.slice.call(arguments, 1);
			do {
				handler.apply(this, applyArgs);
				if (handler.onceFlag === true) {
					container.splice(i, 1);
				} else {
					i += 1;
				}
				handler = container[i];
			} while (handler instanceof Function);
		}

		/*
		 * EVENT BUBBLING
		 */
		i = eventName.lastIndexOf(':');

		/* IF THERE IS A : IN THE EVENT NAME */
		if (i !== -1) {

			/* SLICE THE LAST NAME-SPACE AWAY 
			 * NOTE THAT CHANGING eventName WILL AUTOMATICALLY FILTER INTO THE ARGUMENTS ARRAY
			 * HENCE WE CAN CHANGE THE VARIABLE WITHOUT HAVING TO STORE IN IN ARGUMENTS BEFORE WE CALL APPLY
			 * 
			 * THERE IS A CHROME BUG ON THIS, AS SOON AS THIS IS FIXED WE MAY TRY AGAIN
			 */
			eventName = eventName.slice(0, i);
			//emit.apply(this, arguments);
			/* DO THIS INSTEAD */
			applyArgs = applyArgs || Array.prototype.slice.call(arguments, 1);
			applyArgs.unshift(eventName);
			emit.apply(this, applyArgs);
		}
		return this;
	};

	/* Property: eventListeners
	 * *private*
	 * Event Listener container, best left untouched
	 */
	EventEmitter.prototype.eventListeners = null;

	RDC.setClass('event-emitter', EventEmitter);
}());
/*jslint browser: true*/
/*global RDC*/
RDC.getClass('event-emitter', function (EventEmitter) {
	"use strict";
	function isElm(elm) {
		return !!elm && (elm.nodeType === 1);
	}
	/* Class: DomList
	 * Similiar in functionality to jQuery, but a refined subset. Also focuses purely on the DOM
	 */

	/* Function: constructor
	 * 
	 * Errors:
	 * 1 - The member on index {i} is not an element
	 * 
	 * Parameters:
	 * query - *var* The query can either be a DOM Element, a CSS selector or a Array like structure of elms
	 * 
	 * Example:
	 * (start code)
	 * //css selector
	 * x = new DomList('#some-Id');
	 * //DomElement
	 * y = document.getElementById('#some-Id');
	 * x = new DomList(y);
	 * //Array Like
	 * (function(){
	 *  x = new DomList(arguments);
	 * }(document.getElementById('#some-Id') , document.getElementById('#some-Id2') , document.getElementById('#some-Id3') , document.getElementById('#some-Id4')))
	 * (end)
	 */
	function DomList(query) {
		var list,
			i = 0,
			length;
		this.anims = {};

		if (!!query) {
			/*IF AN ELEMENT WAS PASSED*/
			if (query.nodeType === 1) {
				this.push(query);
				return this;
			/* CSS QUERY */
			} else if (typeof query === 'string') {
				list = document.querySelectorAll(query);
			/* ARRAY-LIKE */
			} else if (
				!query.propertyIsEnumerable('length') ||
					(query instanceof Array)
			) {
				list = query;
			} else {
				throw new Error('Unkown DomList parameter');
			}
			while (i !== list.length) {
				if (isElm(list[i])) {
					i = this.push(list[i]);
				} else {
					throw new Error('The member on index ' + i + ' is not an element');
				}
			}
		}
	}

	DomList.prototype = Object.create(Array.prototype);
	DomList.prototype.constructor = DomList;

	/* Function: addMethod
	 * *static*
	 * This static function was designed to make extending the DomList easier, provide a name and a function and 
	 * addMethod will extend the DomList prototype. When initiated, the method will be called once for every element, passing any arguments
	 * and providing element access through this.
	 * 
	 * Errors:
	 * 1- {name} is already defined on the DomList prototype
	 * 
	 * Parameters:
	 * name - *string* The name of the method to be implemented on all DomList instances
	 * method - *function* The function to be iterated on all DomList instance members
	 * 
	 * Example:
	 * (start code)
	 * DomList.addMethod('unAppend' , function(){
	 *  this.parentNode.removeChild(this);
	 * });
	 * (end)
	 */
	DomList.addMethod = function (name, method) {
		/*IF THE FUNCTION DOES NOT EXIST*/
		if (typeof DomList.prototype[name] === 'undefined') {
			/*WRAP IT IN A METHOD WHICH WILL ITERATE THROUGH THE NODES*/
			DomList.prototype[name] = function () {
				var i = 0,
					elm = this[0];
				while (isElm(elm)) {
					method.apply(elm, arguments);
					i += 1;
					elm = this[i];
				}
				return this;
			};
		} else {
			throw new Error(name + ' is already defined on the DomList prototype');
		}
	};

	/* Function: create
	 * *static*
	 * Creates unappended elements based on the tag descriptor string
	 * 
	 * ( - makes the next element a child
	 * ) - makes the next element a parent
	 * , - makes the next element a sibling
	 * " - makes the contents a text node
	 * 
	 * Errors:
	 * 1 - the braces or " do not match
	 * 
	 * Parameters:
	 * tagString - *string* A descriptor of the structure to create
	 * 
	 * Example:
	 * (start code)
	 * //create a DIV
	 * DomList.create('DIV');
	 * //create a mode complicated structure
	 * DomList.create('DIV,DIV(A("The Hyperlink")),BUTTON(IMG,"Text")');
	 * (end)
	 * 
	 * Returns:
	 * DomList - *<DomList>* A DomList containing the described elements
	 */
	DomList.create = DomList.prototype.create = function (tagString) {
		/*DO SOME CHECKING*/
		if (
			(tagString.split('(').length !== tagString.split(')').length) ||
				/*TO COUNT THE OCCURANCES OF A CHARACTER, SPLIT THEN LENGTH -1*/
				(tagString.split('"').length % 2 !== 1)
		) {
			throw new Error('the braces or " do not match');
		}
		var list = [],
			elm,
			tagName,
			stringFlag,
			parentNode,
			i = 0;
parseTagString:
		while (i !== tagString.length) {
			tagName = '';
captureTag:
			do {
				if (
					!!stringFlag &&
						(tagString[i] !== '"')
				) {
					tagName += tagString[i];
				} else {
					switch (tagString[i]) {
					case '(':/*NEST ONE LOWER*/
					case ')':/*NEST ONE HIGHER*/
					case ',':/*NEST DOES NOT CHANGE*/
						if (tagName) {
							/*APPEND FIRST*/
							break captureTag;
						}
						if (tagString[i] === '(') {
							parentNode = elm;
						} else if (tagString[i] === ')') {
							/*IF WE ARE GOING BACK TO THE TOP LEVEL PARENTNODE SHOULD BE NULL, BUT NOT IN IE8*/
							if (list.indexOf(parentNode) !== -1) {
								parentNode = null;
							} else {
								parentNode = parentNode.parentNode;
							}
						}
						break;
					case '"':/*TEXT NODE*/
						if (stringFlag) {
							i += 1;
							break captureTag;
						}
						stringFlag = true;
						break;
					case undefined:/*RUN OUT OF STRING*/
						if (tagName) {
							break captureTag;
						} else {
							break parseTagString;
						}
					default:
						tagName += tagString[i];
					}
				}
				i += 1;
			/*WHILE TRUE BASICALLY*/
			} while (i);
			if (stringFlag) {
				elm = document.createTextNode(tagName);
				stringFlag = false;
			} else {
				elm = document.createElement(tagName);
			}
			tagName = '';
			if (parentNode) {
				parentNode.appendChild(elm);
			} else {
				list.push(elm);
			}
		}
		return new DomList(list);
	};

	/* Function: addListener
	 * Dom event subscription and normalization, also gives support to mouseenter and mouseleave events in non IE browsers
	 * 
	 * Parameters:
	 * type - *string* The name of the event
	 * handler - *function* The Event Handler
	 * 
	 * Returns:
	 *  handle - *function*  A handle to remove the event with removeListener, note this is not the original function
	 *
	 * Example:
	 * (start code)
	 * //create a DIV
	 * var handle = DomList.create('DIV').addListener('mouseenter' , function(e){...});
	 * (end) 
	 */
	DomList.prototype.addListener = (function () {
		var customEvents;
		function nativeAdd(elm, type, handler) {
			if (typeof elm.addEventListener === 'function') {
				elm.addEventListener(type, handler, false);
			} else {
				elm.attachEvent("on" + type, handler);
			}
		}
		/*NORMALIZE THE EVENT OBJECT*/
		function normalizeEvent(callback) {
			return function eventNormalizer(e) {
				/*GET OLD EVENT*/
				e = e || window.event;
				callback({
					"type"  : e.type,
					"target": e.target || e.srcElement,
					"relatedTarget" : e.relatedTarget || (e.fromElement === e.srcElement) ? e.toElement : e.fromElement,
					"keyCode" : e.charCode || e.keyCode,
					"preventDefault" : function () {
						if (typeof e.preventDefault === 'function') {
							e.preventDefault();
						} else {
							e.returnValue = false;
						}
					},
					"stopPropagation" : function () {
						if (typeof e.stopPropagation === 'function') {
							e.stopPropagation();
						} else {
							e.cancelBubble = true;
						}
					}
				});
			};
		}
		/*CUSTOM EVENTS*/
		customEvents = {
			"mouseenter" : function (elm, type, handler) {
				var fn;
				if (typeof elm.onmouseenter === 'undefined') {
					fn = function (e) {
						var from = e.relatedTarget;
						do {
							if (from === elm) {
								return;
							}
						} while (
							isElm(from) &&
								isElm(from = from.parentNode)
						);
						handler(e);
					};
					type = 'mouseover';
				} else {
					fn = handler;
				}
				nativeAdd(elm, type, fn);
				return fn;
			},
			"mouseleave" : function (elm, type, handler) {
				var fn;
				if (typeof elm.onmouseleave === 'undefined') {
					fn = function (e) {
						var from = e.relatedTarget;
						do {
							if (from === elm) {
								return;
							}
						} while (
							isElm(from) &&
								isElm(from = from.parentNode)
						);
						handler(e);
					};
					type = 'mouseout';
				} else {
					fn = handler;
				}
				nativeAdd(elm, type, fn);
				return fn;
			}
		};
		return function (type, handler) {
			var i = 0,
				length = this.length,
				elm = this[i],
				handle = normalizeEvent(handler),
				engine = customEvents[type] || nativeAdd;
			while (!!elm && elm.nodeType === 1) {
				engine(elm, type, handle);
				i += 1;
				elm = this[i];
			}
			return handle;
		};
	}());

	/* Function: removeListener
	 * *chainable*
	 *  Standard DOM event subscription removal
	 * 
	 * Parameters:
	 * type - *string* The name of the event
	 * handle - *function* A handle to remove the event with removeListener, note this is not the original function
	 * 
	 *
	 * Example:
	 * (start code)
	 * var list = DomList.create('DIV');
	 * //create a DIV
	 * var handle = list.addListener('mouseenter' , function(e){...});
	 * 
	 * list.removeListener('mouseenter' , handle);
	 * 
	 * (end) 
	 */
	DomList.addMethod('removeListener', function (type, handler) {
		if (typeof this.removeEventListener === 'function') {
			this.removeEventListener(type, handler, false);
		} else {
			this.detachEvent('on' + type, handler);
		}
	});



	/* Function: spawn
	 * Creates/adds a child element to each member in the list and returns the new children
	 * 
	 * Parameters:
	 * child - *var* can either be a string descriptor(DomList.create) | Array-or-DomList instance | DOM Element
	 * 
	 * Returns:
	 * The new domlist
	 * 
	 * Example:
	 * (start code)
	 * x = DomList.create('DIV("Hello World!")');
	 * x.spawn('DIV,BUTTON').css({...})// the css is applied to DIV,BUTTON
	 * (end) 
	 */
	DomList.prototype.spawn = function (child) {
		var i = 0,
			elm = this[0],
			list = [],
			spawnList;
		while (isElm(elm)) {
			spawnList = DomList.create(child).appendTo(elm);
			while (spawnList.length !== 0) {
				list.push(spawnList.shift());
			}
			i += 1;
			elm = this[i];
		}
		return new DomList(list);
	};

	/* Function: append
	 * *chainable*
	 *  Creates/adds a child element to each member in the list.
	 * 
	 * Parameters:
	 * child - *var* can either be a string descriptor(DomList.create) | Array-or-DomList instance | DOM Element
	 * 
	 * Example:
	 * (start code)
	 * //create a DIV
	 * DomList.create('DIV("Hello World!")').apendTo(document.body);
	 * //another way
	 * (new DomList('body')).append('DIV("Hello World!")');
	 * (end) 
	 */
	DomList.addMethod('append', function append(child) {
		var i = 0,
			cLength = child.length;
		if (child instanceof Array) {
			while (i !== cLength) {
				this.appendChild(child[i]);
				i += 1;
			}
		} else if (isElm(child)) {
			this.appendChild(child);
		} else {
			append.call(this, DomList.prototype.create(child));
		}
	});

	/* Function: prepend
	 * *chainable*
	 *  Creates/adds(at first index) a child element to each member in the list
	 * 
	 * Parameters:
	 * child - *var* can either be a string descriptor(DomList.create) | Array-or-DomList instance | DOM Element
	 * 
	 * Example:
	 * (start code)
	 * (end) 
	 */
	DomList.addMethod('prepend', function prepend(child) {
		var i = 0,
			cLength = child.length;
		if (child instanceof Array) {
			while (i !== cLength) {
				this.insertBefore(child[i], this.firstChild);
				i += 1;
			}
		} else if (isElm(child)) {
			this.insertBefore(child, this.firstChild);
		} else {
			prepend.call(this, DomList.prototype.create(child));
		}
	});

	/* Function: appendTo
	 * *chainable*
	 * Will append all members of the DomList to the provided element
	 * 
	 * Parameters:
	 * parent - *var* Parent can either be a css selector, a domElement, or a DomList
	 * 
	 * Example:
	 * (start code)
	 * //create a DIV
	 * DomList.create('DIV("Hello World!")').apendTo(document.body);
	 * //another way
	 * (new DomList('body')).append('DIV("Hello World!")');
	 * (end) 
	 */
	DomList.addMethod('appendTo', function appendTo(parent) {
		/*CAPABILITY DETECTION*/
		if (isElm(parent)) {
			parent.appendChild(this);
		} else if (
			(parent instanceof DomList) &&
				(parent.length > 0)
		) {
			parent[0].appendChild(this);
		} else if (typeof parent === 'string') {
			new DomList(parent).append(this);
		} else {
			throw new Error("DomList.appendTo was called without a valid parent");
		}
	});

	/* Function: prependTo
	 * *chainable*
	 * Will prepend all members of the DomList to the provided element
	 * 
	 * Parameters:
	 * parent - *var* Parent can either be a css selector, a domElement, or a DomList
	 * 
	 * Example:
	 * (start code)
	 * //create a DIV
	 * DomList.create('DIV("Hello World!")').prependTo(document.body);
	 * //another way
	 * (new DomList('body')).prepend('DIV("Hello World!")');
	 * (end) 
	 */
	DomList.addMethod('prependTo', function prependTo(parent) {
		/*CAPABILITY DETECTION*/
		if (isElm(parent)) {
			parent.insertBefore(this, parent.firstChild);
		} else if (
			(parent instanceof DomList) &&
				(parent.length > 0)
		) {
			parent[0].insertBefore(this, parent[0].firstChild);
		} else if (typeof parent === 'string') {
			new DomList(parent).prepend(this);
		} else {
			throw new Error("DomList.prependTo was called without a valid parent");
		}
	});

	/* Function: unAppend
	 * *chainable*
	 * This function will loop through each member in the domlist and remove them from their parent
	 * 
	 * Returns:
	 * *DomList* The original list
	 */
	DomList.addMethod('unAppend', function unAppend() {
		/*THIS IS BLOODY SIMPLE*/
		this.parentNode.removeChild(this);
	});

	/* Function getChildren
	 * Will get a child element based on its index to the parent
	 * 
	 * Parameters:
	 * query - *var* Can be either a css selector or a numerical index of which child to get
	 * 
	 * Returns:
	 * children - *DomList* A <DomList> containing the results of the query
	 * 
	 * Example:
	 * (start code)
	 * (new DomList('html')).children(1);
	 * (new DomList('html')).children('body');
	 * (end) 
	 */
	DomList.prototype.getChildren = function getChildren(query) {
		var i = 0,
			ii,
			list = [],
			tempList,
			elm = this[0];
nextElm:
		while (isElm(elm)) {
			switch (typeof query) {
			case 'string':
				tempList = elm.querySelectorAll(query);
				break;
			case 'number':
				if (isElm(elm.children[query])) {
					tempList = [elm.children[query]];
				}
				break;
			case 'undefined':
				tempList = elm.children;
				break;
			}
			for (ii = 0; ii < tempList.length; ii += 1) {
				list.push(tempList[ii]);
			}
			i += 1;
			elm = this[i];
		}
		return new DomList(list);
	};

	/* Function getParent
	 * Will get a child element based on its index to the parent
	 * 
	 * Parameters:
	 * query - *var* Can be either a css selector or a numerical index of which child to get
	 * 
	 * Returns:
	 * children - *DomList* A <DomList> containing the results of the query
	 * 
	 * Example:
	 * (start code)
	 * (new DomList('html')).children(1);
	 * (new DomList('html')).children('body');
	 * (end) 
	 */
	DomList.prototype.getParent = function getParent() {
		var i = -1,
			list = new DomList(),
			elm;
		while (isElm(elm = this[i += 1])) {
			list.push(elm.parentNode);
		}
		return list;
	};

	/* Function: removeChildren
	 * *chainable*
	 * Will empty the DomList members of all their children 
	 */
	DomList.addMethod('removeChildren', function removeChildren() {
		while (!!this.firstChild) {
			this.removeChild(this.firstChild);
		}
	});

	/* Function: attr
	 * *chainable*
	 * Get or Set an attribute, works like jQuery.
	 * 
	 * 1. - Gets an attribute if one argument is passed.
	 * 2. - Sets an attribute if two arguments are passed.
	 * 3. - Sets multiple attributes if an object is passed.
	 * 
	 * Parameters:
	 * arg1 - *var* Can either be the name of the attribute to get or set, or an object with name value pairs
	 * arg2 - *string* The value to set to the attribute(arg1)
	 * 
	 * Returns:
	 * Either the retrieved attribute or the domList, depending on wether it was a get or a set.
	 * 
	 * Example:
	 * (start code)
	 * x = new DomList('html')
	 * //1
	 * x.attr('id'); //get the id
	 * //2
	 * x.attr('id' , 'new-id'); //set the id
	 * //3
	 * x.attr({
	 *  'id' : 'another-new-id',
	 *  'class' : 'some-class-name'
	 * });//set the id and the class
	 * (end) 
	 */
	DomList.prototype.attr = (function () {
		var engine = {
			"get" : {
				"value" : function (elm) {
					if (elm.tagName === 'SELECT') {
						if (elm.selectedIndex === -1) {
							return '';
						} else {
							return elm.options[elm.selectedIndex].value;
						}
					} else if (elm.type === 'checkbox') {
						return elm.checked;
					}
					return elm.value;
				}
			},
			"set" : {
				"value" : function (elm, val1) {
					if (elm.tagName === 'SELECT') {
						var children = elm.querySelectorAll('option'),
							selectedIndex = 0;
						while (selectedIndex < children.length) {
							if (children[selectedIndex].value === val1.toString()) {
								elm.selectedIndex = selectedIndex;
								return;
							}
							selectedIndex += 1;
						}
						elm.selectedIndex = -1;
					} else if (elm.type === 'checkbox') {
						elm.checked = !!val1;
					} else {
						elm.value = val1;
					}
				}/*,
				"action": function (elm, val) {
					elm.action = val;
				}*/
			}
		};
		return function (arg1, arg2) {
			var i = 0,
				elm = this[i],
				a2;
			switch (typeof arg1) {
			case "string":
				if (arguments.length === 2) {
nextElm:			while (isElm(elm)) {
						if (arg2 instanceof Function) {
							a2 = arg2(i);
						} else if (arg2 instanceof Array) {
							a2 = arg2[i];
						} else {
							a2 = arg2;
						}
						if (engine.set.hasOwnProperty(arg1)) {
							engine.set[arg1](elm, a2);
						} else if (a2 === null) {
							elm.removeAttribute(arg1);
						} else {
							elm.setAttribute(arg1, a2);
						}
						i += 1;
						elm = this[i];
					}
				} else {
					if (engine.get.hasOwnProperty(arg1)) {
						return engine.get[arg1](this[0]);
					} else {
						return this[0].getAttribute(arg1);
					}
				}
				break;
			case 'object':
				for (i in arg1) {
					if (arg1.hasOwnProperty(i)) {
						this.attr(i, arg1[i]);
					}
				}
				break;
			}
			return this;
		};
	}());

	/* Function: createClassToggler
	 * *chainable*
	 * Will add the class into the list is its not already there
	 * 
	 * Parameters:
	 * className - *string* The class name to add
	 */
	DomList.prototype.createClassToggler = function createClassToggler(list) {
		var dlist = this;
		function classToggler(name) {
			var index;
			/*IF THEY WANT A DIFFERENT CLASS*/
			if (name !== classToggler.current) {
				index = list.indexOf(name);
				/*CHECK THAT THE CLASS IS IN THE LIST*/
				if (index !== -1) {
					dlist.removeClass(classToggler.current);
					dlist.addClass(classToggler.current = name);
					classToggler.index = index;
				} else {
					throw new Error('Domlist ClassToggler:' + JSON.stringify(list) + ' could not toggle class ' + name);
				}
			}
		}
		classToggler.index = -1;
		classToggler.current = '';
		classToggler.next = function next() {
			if (classToggler.index === list.length - 1) {
				classToggler(list[0]);
			} else {
				classToggler(list[classToggler.index + 1]);
			}
		};
		classToggler.previous = function previous() {
			if (classToggler.index < 1) {
				classToggler(list[list.length - 1]);
			} else {
				classToggler(list[classToggler.index - 1]);
			}
		};
		return classToggler;
	};

	/* Function: addClass
	 * *chainable*
	 * Will add the class into the list is its not already there
	 * 
	 * Parameters:
	 * className - *string* The class name to add
	 */
	DomList.addMethod('addClass', function addClass(className) {
		var list = this.className.split(' '),
			i = 0;
		if (list.indexOf(className) === -1) {
			while (i < list.length) {
				if (!!list[i]) {
					className += ' ' + list[i];
				}
				i += 1;
			}
			this.className = className;
		}
	});

	/* Function: removeClass
	 * *chainable*
	 * Will remove the class from the list if its there.
	 * 
	 * Parameters:
	 * className - *string* The class name to remove
	 */
	DomList.addMethod('removeClass', function removeClass(className) {
		var list = this.className.split(' '),
			index = list.indexOf(className),
			i = 0;
		if (index !== -1) {
			list.splice(index, 1);
			if (list.length === 0) {
				this.className = '';
			} else {
				className = list[i];
				i += 1;
				while (i < list.length) {
					if (!!list[i]) {
						className += ' ' + list[i];
					}
					i += 1;
				}
				this.className = className;
			}
		}
	});

	/* Function: css
	 * *chainable*
	 * Get or Set a css attribute, works like jQuery.
	 * 
	 * 1. - Gets a css attribute if one argument is passed.
	 * 2. - Sets a css attribute if two arguments are passed.
	 * 3. - Sets multiple attributes if an object is passed.
	 * 
	 * Parameters:
	 * arg1 - *var* Can either be the name of the css attribute to get or set, or an object with name value pairs
	 * arg2 - *string* The value to set to the css attribute(arg1)
	 * 
	 * Returns:
	 * Either the retrieved attribute or the domList, depending on wether it was a get or a set.
	 * 
	 * Example:
	 * (start code)
	 * x = new DomList('html')
	 * //1
	 * x.css('padding-top'); //get the id
	 * //2
	 * x.css('padding-top' , '10px'); //set the id
	 * //3
	 * x.css({
	 *  'padding-top' : '10px',
	 *  'padding-left' : '10px'
	 * });//set the id and the class
	 * (end) 
	 */
	DomList.prototype.css = (function () {
		var elmIndex = [],
			cache = [];
		function getHex(rgba) {
			var RGBA = rgba.replace(/(rgba\(|\)| )/g, '').split(',');
			return '#' + getHex.tostr(Math.round(255 * RGBA[3])) + getHex.tostr(RGBA[0]) + getHex.tostr(RGBA[1]) + getHex.tostr(RGBA[2]);
		}
		getHex.tostr = function (num) {
			var ret = (+num).toString(16);
			if (ret.length === 1) {
				return '0' + ret;
			}
			return ret;
		};
		return function css(arg1, arg2) {
			var i = 0,
				elm = this[0],
				jsCss = '',
				cacheIndex,
				commit,
				a2;
			switch (typeof arg1) {
			case "string":
				while (i < arg1.length) {
					if (arg1[i] === '-') {
						i += 1;
						jsCss += arg1[i].toUpperCase();
					} else {
						jsCss += arg1[i];
					}
					i += 1;
				}
				i = 0;
				if (arguments.length === 2) {
					commit = function () {
						if (!cache[cacheIndex][jsCss]) {
							cache[cacheIndex][jsCss] = css.call({"0": elm}, arg1);
						}
						elm.style[jsCss] = a2;
					};
					while (isElm(elm)) {
						if (arg2 instanceof Function) {
							a2 = arg2(i);
						} else if (arg2 instanceof Array) {
							a2 = arg2[i];
						} else {
							a2 = arg2;
						}
						cacheIndex = elmIndex.indexOf(elm);
						if (cacheIndex === -1) {
							cacheIndex = cache.push({}) - 1;
							elmIndex.push(elm);
						}
						/*RETURN TO DEFAULT*/
						if (a2 === '__default__') {
							/*IF IT HAS BEEN CHANGED THEN CHANGE IT BACK*/
							if (!!cache[cacheIndex][jsCss]) {
								css.call({"0" : elm}, arg1, cache[cacheIndex][jsCss]);
							}
						} else {
						/*STORE THE DEFAULT IF ITS FIRST TIME*/
							switch (jsCss) {
							case "opacity":
								if (typeof elm.style.opacity === 'undefined' && typeof elm.filters === 'object') {
									try {
										elm.filters.item('DXImageTransform.Microsoft.Alpha').opacity = Math.round(a2 * 100);
									} catch (ex) {
										elm.style.filter += 'progid:DXImageTransform.Microsoft.Alpha(opacity=' + Math.round(a2 * 100) + ')';
									}
									break;
								}
								commit();
								break;
							case (a2.indexOf('rgba') !== -1 && 'backgroundColor'):
								try {
									commit();
								} catch (e) {
									try {
										if (elm.className.indexOf(' __has_filter__') === -1) {
											elm.className += ' __has_filter__';
										}
										elm.filters[0].startColorstr = elm.filters[0].endColorstr = getHex(a2);
									} catch (er) {}
								}
								break;
							default:
								commit();
								break;
							}
						}
						i += 1;
						elm = this[i];
					}
				} else {
					if (typeof window.getComputedStyle === 'function') {
						/*FF 3.6 NEEDS A SECOND NULL ARGUMENT*/
						return window.getComputedStyle(this[0], null).getPropertyValue(arg1);
					} else {
						/*CURRENT STYLE IS ASYNCHRONOUS*/
						if (!!this[0].currentStyle) {
							return this[0].currentStyle[arg1];
						} else {
							return undefined;
						}
					}
				}
				break;
			case 'object':
				for (i in arg1) {
					if (arg1.hasOwnProperty(i)) {
						this.css(i, arg1[i]);
					}
				}
				break;
			}
			return this;
		};
	}());

	/* Function: animate
	 * Provides a very simple but flexible platform in which to create custom animations. 
	 * There is no actual animation abstraction, this is basically a timer
	 * 
	 * Parameters:
	 * name - *string* The name of the animation(generally the property that is being animated)
	 * config - *optional* This provides configuration to the animation, which will cause the animation to execute accepts
	 * - to *required* The finishing value of the step
	 * - from *optional* The starting value of the step, defaults to 0 the first time or the previous value
	 * - for *optional* The duration of the animation, defaults to 300ms
	 * 
	 * Returns:
	 * timer - *EventEmitter* An event-emitter which emits four events
	 * 
	 * Events:
	 * start - The start of the loop
	 * - *arg1* The domlist which is being animated
	 * loop - An iteration of the animation
	 * - *arg1* The domlist which is being animated
	 * - *arg2* The step of the animation. Value of how close the animation is to finishing
	 * end - The natural end of the loop
	 * - *arg1* The domlist which is being animated
	 * stop - The animation has been artificially stopped
	 * - *arg1* The domlist which is being animated
	 * 
	 * Example:
	 * (start code)
	 * //get the domlist
	 * x = new DomList('html')
	 * //configure the animation
	 * x.animate('background').on('start' , function(list){...}).on('loop' , function(list , step){
	 *  list.css('background-color' , 'rgb(100,100,' + step + ')');
	 * });
	 * //on load animate blue from 255 to 100
	 * x.addListener('load' , function(){
	 *  x.animate('background' , {
	 *   "to" : 100,
	 *   "from" : 255
	 *  });
	 * });
	 * //on click animate background-blue to 200 from whatever it is now , or from 0 if clicked before load
	 * x.addListener('click' , function(){
	 *  x.animate('background' , {
	 *   "to" : 200,
	 *   "for" : 900
	 *  });
	 * });
	 * (end) 
	 */
	DomList.prototype.animate = (function () {
		function Timer() {
			EventEmitter.apply(this);
			/*this.on({
				"end" : EventEmitter,
				"stop" : EventEmitter
			});*/
		}
		Timer.prototype = Object.create(EventEmitter.prototype);
		Timer.prototype.start = function () {
			var self = this,
				startTime = Date.now(),
				go = self.goObj = {};
			self.emit('start', self.domList);
		    (function loop() {
				var currentTime = Date.now() - startTime;
		        if (self.goObj === go && currentTime < self['for']) {
					self.current = self.from + (self.to - self.from) * (Math.sin(Math.PI * (currentTime / self['for'] - 0.5)) / 2 + 0.5);
					self.emit('loop', self.domList, self.current);
					setTimeout(loop, 16);
		        } else if (self.goObj === go) {
					self.emit('loop', self.domList, self.to);
					self.emit('end', self.domList);
		        }
		    }());
		};
		Timer.prototype.stop = function () {
			this.emit('stop');
			this.goObj = null;
		};
		Timer.prototype['for'] = 300;
		Timer.prototype.from = 0;
		Timer.prototype.current = 0;


		return function (name, config) {
			var timer;
			if (typeof name !== 'string') {
				throw new Error('First argument to animation must be a string');
			}
			if (this.anims[name] instanceof Timer) {
				this.anims[name].stop();
			} else {
				this.anims[name] = new Timer();
			}
			timer = this.anims[name];
			timer.domList = this;
			if (!!config && typeof config === 'object') {
				if (typeof config.to === 'number') {
					timer.to = config.to;
				} else {
					throw new Error('config object must provide a number to value');
				}
				if (typeof config.from === 'number') {
					timer.from = config.from;
				} else {
					timer.from = timer.current;
				}
				if (typeof config['for'] === 'number') {
					timer['for'] = config['for'];
				}
				setTimeout(function () {
					timer.start();
				}, config.wait || 20);
			}
			return timer;
		};
	}());

	/* Function: each
	 * *chainable*
	 * Each is like forEach but it returns the DomList, allowing chaining
	 *
	 * Parameters:
	 * callback - *function*
	 */
	DomList.prototype.each = function each(callback) {
		this.forEach(callback);
		return this;
	};

	/* Property: anims
	 * *private*
	 * A container of all existing animations, This is best to be left alone unless the deeper workings are known
	 */
	DomList.prototype.anims = null;

	RDC.setClass('domlist', DomList);
});
/*jslint browser:true nomen:true */
/*
 * GOOGLE ANALYTICS TRACKING DATA
 */
var _gaq = [
	/* ACCOUNT DETAILS ARE DIFFERENT FOR EACH HOST */
	[
		'_setAccount',
		{
			'www.permaconn.com.au': 'UA-28273223-1',
			'www.permaconn.co.nz': 'UA-27236547-1'
		}[location.host]
	],

	/* STANDARD */
	['_trackPageview']
];

(function checkReady(DOMContentLoaded) {
	"use strict";
	if (
		!!document.body &&
			(document.body.nodeType === 1)
	) {
		setTimeout(DOMContentLoaded, 100);
	} else if (!!document.addEventListener) {
		document.addEventListener('DOMContentLoaded', DOMContentLoaded, false);
	} else {
		window.attachEvent('onload', DOMContentLoaded);
	}
}(function () {
	"use strict";
	var docElement = document.documentElement,
		docBody = document.body;

	/*
	 * TO GIVE STATE TO SCROLL WE STORE SCROLL
	 * IN LOCAL STORAGE EVERYTIME
	 * THE USER SCROLLS
	 */
	window.onscroll = function () {
		localStorage.scroll = docElement.scrollTop || docBody.scrollTop;
	};

	/*
	 * SET SCROLL FROM THE LOCAL STORAGE
	 */
	docBody.scrollTop = docElement.scrollTop = +localStorage.scroll;

	/* BUILD THE
	 * SIDE MENU
	 */
	window.RDC.getClass([
		'domlist'
	], function (DomList, CONFIG) {
		/* GET THE SIDEBAR LINKS */
		var links = new DomList('html > body > div#viewport > div#side-menu > div > a'),
			/* GET THE SLIDESHOW CONTAINER */
			slideContainer = new DomList('#slideshow').addClass('moving'),
			i = 1;

		/*
		 * MAKE THE SIDEBAR HAPPEN
		 */
		setInterval(function () {
			slideContainer.removeClass('img' + i);
			i += 1;
			if (i === 6) {
				i = 1;
			}
			slideContainer.addClass('img' + i);
		}, 5e3);

		/* WHEN YOU CLICK ON EITHER TWO OF THE LINKS
		 * WE TOGGLE THE VISIBLE CLASS ON AND OFF
		 */
		links.addListener('click', function (e) {
			var container = new DomList(e.target.parentNode);
			if (container[0].className.indexOf('visible') !== -1) {
				container.removeClass('visible');
			} else {
				container.addClass('visible');
			}
			e.preventDefault();
		});

		/* IF WE ARE INSIDE EITHER THE SAFELINK OR PERMACONN SOLUTIONS PART OF THE PAGE
		 * IT WOULD BE NICE TO HAVE THE SIDE BAR AUTOMAITCALLY OPEN
		 */
		if (location.pathname.indexOf('/solutions/permaconn') === 0) {
			(new DomList('html > body > div#viewport > div#side-menu > div'))[0].className = 'visible';
		} else if (location.pathname.indexOf('/solutions/safe') === 0) {
			(new DomList('html > body > div#viewport > div#side-menu > div'))[1].className = 'visible';
		}
	});
}));

