/* Bent Live: cached v:1.21.16 */ 
var un = undefined, undef = undefined;

var jj = {

	
	bind: function (object, func) {
		if (arguments.length > 2) {
			var args = jj.argsSlice (arguments, 2);
			if (typeof (func) == 'string') {
				return function () {
					return object [func].apply (object, jj.join (args, jj.argsSlice (arguments)));
				};
			} else {
				return function () {
					return func.apply (object, jj.join (args, jj.argsSlice (arguments)));
				};
			}
		} else {
			if (typeof (func) == 'string') {
				return function () {
					return object [func].apply (object, arguments);
				};
			} else {
				return function () {
					return func.apply (object, arguments);
				};
			}
		}
	},

	
	utfLen: function (data) {
		var ret = 0;
		for (var i = 0; i < data.length; i++) {
			var c = data.charCodeAt (i);
			if (c < 0x80) ret += 1;
			else if (c < 0x800) ret += 2;
			else if (c < 0x10000) ret += 3;
			else if (c < 0x200000) ret += 4;
			else if (c < 0x4000000) ret += 5;
			else ret += 6;
		}
		return ret;
	},

	
	errorSummary: function (error) {
		switch (typeof error) {
		case 'string':
			return error;
		case 'object':
			if ('fileName' in error)
				return error.fileName + ':' + error.lineNumber + ' ' + 
					error.message + ' (' + error.name + ')';
			else return error.message;
		default:
			return jj.pretty (error);
		}
	},

		
	leadingZero: function (value) {
		return String(value).length < 2 ? '0'+value : String(value);
	},
		
	returnNumeric: function (input) {
		return input.replace(/[^0-9]+/g,'');
	},

	min: function () {
		var value = undefined;
		for (var i = 0; i < arguments.length; i++)
			if (value == undefined || value > arguments [i])
				value = arguments [i];
		return value;
	},

	max: function () {
		var value = undefined;
		for (var i = 0; i < arguments.length; i++)
			if (value == undefined || value < arguments [i])
				value = arguments [i];
		return value;
	},

	
	def: function () {
		var name = arguments [0];
		var props = arguments [arguments.length - 1];

		
		if (! (name in props))
			throw 'Constructor not found: ' + name;

		
		var classObj = {
			name: name,
			props: props
		};

		
		var ret = function () {
			this [name].apply (this, arguments);
		};
		ret.name = name;

		
		ret.prototype.__class = classObj;

		
		jj.mergeIntoNew (ret.prototype, props);

		
		for (var i = arguments.length - 2; i >= 1; i--)
			jj.mergeIntoNew (ret.prototype, arguments [i].prototype);

		
		return ret;
	},

	

	merge: function () {
		var dest = {};
		for (var i = 0; i < arguments.length; i++) {
			jj.mergeInto (dest, arguments [i]);
		}
		return dest;
	},

	
	mergeInto: function () {
		var dest = arguments [0];
		for (var i = 1; i < arguments.length; i++) {
			var src = arguments [i];
			for (var key in src)
				dest [key] = src [key];
		}
		return dest;
	},

	
	mergeIntoReal: function (dest, srcs) {
		for (var i = 0; i < srcs.length; i++) {
			var src = srcs [i];
			for (var key in src)
				dest [key] = src [key];
		}
	},

	
	mergeIntoNew: function () {
		var dest = arguments [0];
		for (var i = 1; i < arguments.length; i++) {
			var src = arguments [i];
			for (var key in src) {
				if (! (key in dest))
					dest [key] = src [key];
			}
		}
	},

	
	mergeIntoNewReal: function (dest, srcs) {
		for (var i = 0; i < srcs.length; i++) {
			var src = srcs [i];
			for (var key in src) {
				if (! (key in dest))
					dest [key] = src [key];
			}
		}
	},

	
	callSummary: function (name, args) {
		var s = name + ' (';
		if (jj.isArray (args) || jj.isArguments (args)) {
			var first = true;
			for (var i = 0; i < args.length; i++) {
				if (! first) s += ', ';
				s += jj.pretty (args [i]);
				first = false;
			}
		} else if (jj.isMap (args)) {
			var first = true;
			for (var i in args) {
				if (! first) s += ', ';
				s += i + ': ' + jj.pretty (args [i]);
				first = false;
			}
		} else if (args == undefined) {
			s += 'undefined';
		} else {
			s += '?' + jj.pretty (args) + '?';
		}
		return s + ')';
	},

	
	handle: function (handlerAny, funcName, args) {
		switch (typeof (handler)) {

		case 'function':
			return handlerAny (funcName, args);

		case 'object':
			return handerAny [funcName].apply (handlerAny, jj.isArray (args)? args : [ args ]);

		default:
			throw 'Eek';
		}
	},

	handlerFunc: function (handlerAny, errorIfNotFound, prefix) {

		if (jj.isUndefined (errorIfNotFound))
			errorIfNotFound = true;

		if (jj.isUndefined (prefix))
			prefix = '';

		switch (typeof (handlerAny)) {

		case 'function':
			return handlerAny;

		case 'object':
			var rest = jj.argsSlice (arguments, 3);
			return function (name, args) {

				
				if (prefix + 'before' in handlerAny) {
					handlerAny [prefix + 'before'].apply (handlerAny, jj.join (rest, [ name, args ]));
				}

				var retVal;
				if (prefix + name in handlerAny) {

					
					if (jj.isArray (args)) {
						retVal = handlerAny [prefix + name].apply (handlerAny, args);
					} else if (jj.isMap (args)) {
						var fn = handlerAny [prefix + name];
						if (fn.length == 0) {
							retVal = fn.apply (handlerAny, jj.join (rest, [ ]));
						} else if (fn.length == 1) {
							retVal = fn.apply (handlerAny, jj.join (rest, [ args ]));
						} else if (fn.length == 2) {
							retVal = fn.apply (handlerAny, jj.join (rest, [ name, args ]));
						}
					} else {
						retVal = handlerAny [prefix + name].apply (handlerAny, rest);
					}

				} else if (prefix + 'any' in handlerAny) {

					
					return handlerAny [prefix + 'any'].apply (handlerAny, jj.join (rest, [ name, args ]));

				} else if (errorIfNotFound) {

					
					throw 'No handler for ' + name;
				}

				
				if (prefix + 'after' in handlerAny) {
					handlerAny [prefix + 'after'].apply (handlerAny, jj.join (rest, [ name, args ]));
				}

				return retVal;
			};

		case 'undefined':
			return function (name, args) {
			};

		default:
			throw 'Eek ' + typeof (handlerAny);
		}
	},
	
	
	handlerFuncSpecial: function (mainObject, childObject) {
		return function (name, args) {
			if (! (name in childObject))
				throw 'No handler for ' + name;
			return childObject [name].apply (mainObject, args);
		};
	},

	
	copy: function (data) {

		if (data == undefined) {
			return undefined;
		}

		if (typeof data == 'null') {
			return data;
		}

		if (typeof data == 'number') {
			return data;
		}

		if (typeof data == 'string') {
			return data;
		}

		if (jj.isArray (data)) {
			var ret = [];
			for (var i in data)
				ret.push (jj.copy (data [i]));
			return ret;
		}

		if (jj.isMap (data)) {
			var ret = {};
			for (var i in data)
				ret [i] = data [i];
			return ret;
		}

		if (typeof data == 'boolean') {
			return data;
		}

		throw 'Trying to copy ' + data;
	},

	eq: function () {

		if (arguments.length < 1)
			throw new Exception ('Not enough arguments for jj.eq');

		for (var i = 1; i < arguments.length; i++) {
			if (! jj.eqReal (arguments [0], arguments [i])) {
				return false;
			}
		}

		return true;
	},

	eqReal: function (left, right) {

		if (left == null)
			return right == null;

		if (typeof left == 'undefined')
			return typeof right == 'undefined';

		if (typeof left == 'number')
			return typeof right == 'number' && left == right;

		if (typeof left == 'boolean')
			return typeof right == 'boolean' && left == right;

		if (typeof left == 'string')
			return typeof right == 'string' && left == right;

		if (typeof left == 'object' && left instanceof Array)
			return typeof right == 'object' && right instanceof Array && jj.eqArray (left, right);

		if (jj.isMap (left))
			return jj.isMap (right) && jj.eqMap (left, right);

		throw 'Don\'t know how to handle ' + typeof left;
	},

	eqMap: function (left, right) {

		
		for (var i in left) {
			if (! (i in right))
				return false;
			if (! jj.eqReal (left [i], right [i]))
				return false;
		}

		
		for (var i in right) {
			if (! (i in left))
				return false;
		}

		
		return true;
	},

	eqArray: function (left, right) {

		if (left.length != right.length)
			return false;

		for (var i in left) {
			if (! jj.eqReal (left [i], right [i]))
				return false;
		}
		
		return true;
	},

	propNameRegexp: /^[a-zA-z_][a-zA-Z0-9_]*$/,

	
	pretty: function (data) {

		if (data == undefined) {
			return 'undefined';
		}

		if (typeof data == 'number') {
			return '' + data;
		}

		if (typeof data == 'string') {
			return '\'' + data
				.replace (/\u005c/g, '\\\\')
				.replace (/\u0027/g, '\\\'')
				.replace (/\u0000/g, '\\u0000')
				.replace (/\u0008/g, '\\b')
				.replace (/\u0009/g, '\\t')
				.replace (/\u000a/g, '\\n')
				.replace (/\u000b/g, '\\v')
				.replace (/\u000c/g, '\\f')
				.replace (/\u000d/g, '\\r')
				+ '\'';
		}

		if (typeof data == 'array' || data.constructor == Array) {
			s = '[ ';
			var first = true;
			for (var i = 0; i < data.length; i++) {
				if (! first) s += ', ';
				s += jj.pretty (data [i]);
				first = false;
			}
			return s + ' ]';
		}

		if (typeof data == 'object') {
			var s = '{ ';
			var first = true;
			for (var key in data) {
				if (! first) s += ', ';
				s += (jj.propNameRegexp.test (key)? key : jj.pretty (key))
					+ ': ' + jj.pretty (data [key]);
				first = false;
			}
			return s + ' }';
		}

		if (typeof data == 'boolean') {
			return data? 'true' : 'false';
		}

		if (typeof data == 'function') {
			return 'function(...){...}';
		}

		throw 'Trying to encode ' + data;
	},

	inx: function (left ) {
		for (var i = 1; i < arguments.length; i++) {
			if (left == arguments [i])
				return true;
		}
		return false;
	},

	arrayToSet: function (array) {
		var ret = {};
		for (var i = 0; i < array.length; i++)
			ret [array [i]] = true;
		return ret;
	},

	setToArray: function (set) {
		var ret = [];
		for (var key in set)
			ret.push (key);
		return ret;
	},
	objectToArray: function (obj) {
		var ret = [];
		for (var key in obj)
			ret.push (obj[key]);
		return ret;
	},

	map: function () {
		var ret = {};
		for (var i = 0; i < arguments.length; i += 2) {
			ret [arguments [i]] = arguments [i + 1];
		}
		return ret;
	},

	mapKeys: function (map) {
		var ret = [];
		for (var key in map)
			ret.push (key);
		return ret;
	},

	mapNumberKeys: function (map) {
		var ret = [];
		for (var key in map)
			ret.push (Number (key));
		return ret;
	},

	numberSetToArray: function (set) {
		var ret = [];
		for (var i in set)
			ret.push (Number (i));
		return ret;
	},

	stringSetToArray: function (set) {
		var ret = [];
		for (var i in set)
			ret.push (String (i));
		return ret;
	},

	mapValues: function (map) {
		var ret = [];
		for (var i in map)
			ret.push (map [i]);
		return ret;
	},
	
	randomArray: function (in_array, in_len) {
		var ret = [];
		var present = [];
		for (var i= 0; i<in_len; i++){
			var random = Math.floor (in_array.length * Math.random ());
			if(!this.inArray(random,present)){
				present.push(random);
				ret.push (in_array[random]);
			}
		}
		return ret;
	},
	
	ArrayAminusB: function (in_a, in_b) {
	var ret = [];
	var newValue = false;
	for(var i = 0 ; i<in_a.length; i++){
		if((!this.inArray(in_a[i],in_b))){
			ret.push(in_a[i]);
		}
	}
	return ret;
	},
	
	isArray: function (any) {
		if (typeof any != 'object') return false;
		if (! (any instanceof Array)) return false;
		return true;
	},

	isMap: function (object) {
		if (typeof object != 'object') return false;
		if (object == null) return false;
		if (object.constructor != Object && object instanceof object.constructor) return false;
		return true;
	},

	isRegExp: function (any) {
		if (typeof any != 'function') return false;
		if (any.constructor != RegExp) return false;
		return true;
	},

	isString: function (any) {
		return typeof any == 'string';
	},

	isInt: function (any) {
		return typeof any == 'number' && Math.floor (any) == any;
	},

	isIntArray: function (any) {
		if (! jj.isArray (any)) return false;
		for (var i = 0; i < any.length; i++) {
			if (! jj.isInt (any [i])) return false;
		}
		return true;
	},

	isStringArray: function (any) {
		if (! jj.isArray (any)) return false;
		for (var i = 0; i < any.length; i++) {
			if (! jj.isString (any [i])) return false;
		}
		return true;
	},

	flatten: function (src) {
		var dst = [];
		for (var i = 0; i < arguments.length; i++)
			jj.flattenReal (dst, arguments [i]);
		return dst;
	},

	flattenReal: function (dst, src) {
		if (jj.isArray (src)) {
			for (var i = 0; i < src.length; i++) {
				jj.flattenReal (dst, src [i]);
			}
		} else {
			dst.push (src);
		}
	},

	alert: function () {
		switch (arguments.length) {
		case 1:
			return alert (jj.pretty (arguments [0]));
		case 2:
			return alert (jj.callSummary (arguments [0], arguments [1]));
		default:
			throw 'Invalid number of args for jj.alery: ' + arguments.length;
		}
	},

	isObject: function (any) {
		return typeof any == 'object';
	},

	isBoolean: function (any) {
		return typeof any == 'boolean';
	},

	isFunction: function (any) {
		return typeof any == 'function';
	},

	prettyArgs: function (args) {
		var s = '(';
		for (var i = 0; i < args.length; i++) {
			if (i > 0) s += ', ';
			s += jj.pretty (args [i]);
		}
		return s + ')';
	},

	argsSlice: function (args, offset, length) {
		if (offset == undefined) offset = 0;
		if (length == undefined) length = args.length - offset;
		if (length < 0) length = 0;
		var ret = Array (length);
		for (var i = offset, j = 0; i < offset + length; i++, j++) {
			ret [j] = i < args.length? args [i] : undefined;
		}
		return ret;
	},

	isUndefined: function (any) {
		return any === undefined;
	},

	isNull: function (any) {
		return any === null;
	},

	createNamedElement: function( type, name ) {
		var element;
		try {
			element = document.createElement('<'+type+' name="'+name+'">');
		} catch (e) { }
		if (!element || !element.name) { 
			element = document.createElement(type);
			element.name = name;
		}
		return element;
	},

	inArray: function (search, array) {
		for (var i = 0; i < array.length; i++) {
			if (array [i] === search) return true;
		}
		return false;
	},

	randomChoice: function (array) {
		return array [Math.floor (array.length * Math.random ())];
	},

	anyInArray: function (searches, array) {
		for (var i = 0; i < searches.length; i++) {
			for (var j in array)
				if (array[j] == searches[i]) return true;
		}
		return false;
	},

	join: function () {
		var ret = [];
		return ret.concat.apply (ret, jj.argsSlice (arguments));
	},

	joinInto: function (arr) {
		for (var i = 1; i < arguments.length; i++) {
			for (var j = 0; j < arguments [i].length; j++) {
				arr.push (arguments [i] [j]);
			}
		}
		return arr;
	},

	coalesce: function () {
		for (var i = 0; i < arguments.length; i++) {
			if (arguments [i] != null && arguments [i] != undefined)
				return arguments [i];
		}
		return undefined;
	},

	arrayDel: function (array, elem) {
		var i = array.indexOf (elem);
		if (i >= 0) {
			array.splice (i, 1);
		}
	},

	firstToUpper: function (str) {
		if (str.length == 0) return '';
		return str.substr (0, 1).toUpperCase () + str.substr (1);
	},

	pluralize: function (num, singular, plural) {
		if (! plural) plural = singular + 's';
		if (num == 1) return '1 ' + singular;
		return String (num) + ' ' + plural;
	},

	toYmd: function (date) {
		return '' +
			jj.zeroPad (date.getFullYear (), 4) + '-' +
			jj.zeroPad (date.getMonth () + 1, 2) + '-' +
			jj.zeroPad (date.getDate (), 2);
	},

	zeroPad: function (num, digits) {
		var s = String (num);
		while (s.length < digits)
			s = '0' + s;
		return s;
	},

	numberFormat: function (num, before, after) {
		var prefix = jj.zeroPad (Math.floor (num), before);
		num = Math.abs (num);
		num = num - Math.floor (num);
		for (var i = 0; i < after; i++) num = num * 10;
		num = Math.round (num);
		var suffix = String (num)
		while (suffix.length < after) suffix = '0' + suffix;
		return prefix + '.' + suffix;
	},

	mapHas: function (map, name) {
		return Object.prototype.propertyIsEnumerable.apply (map, [ name ]);
	},

	mapCount: function (map) {
		var ret = 0;
		for (var key in map) ret++;
		return ret;
	},

	isArguments: function (any) {
		if (typeof any != 'object') return false;
		if (jj.mapCount (any) != 0) return false;
		if (! Object.prototype.hasOwnProperty.apply (any, [ 'length' ])) return false;
		return true;
	},

	mapEmpty: function (map) {
		for (var key in map) { return false; }
		return true;
	},

	
	arrayMerge: function () {
		var set = {}, ret = [];
		for (var i = 0; i < arguments.length; i++) {
			for (var j = 0; j < arguments [i].length; j++) {
				var val = arguments [i] [j];
				if (set [val]) continue;
				set [val] = true;
				ret.push (val);
			}
		}
		return ret;
	},
	
	arrayMergeInto: function (dst) {

		
		var set = {};
		for (var j = 0; j < dst.length; j++) {
			set [dst [j]] = true;
		}

		
		for (var i = 1; i < arguments.length; i++) {
			for (var j = 0; j < arguments [i].length; j++) {
				var val = arguments [i] [j];
				if (set [val]) continue;
				set [val] = true;
				dst.push (val);
			}
		}

		
		return dst;
	},
	
	arrayDiff: function (plus) {
		var set = {}, ret = [];
		for (var i = 1; i < arguments.length; i++) {
			for (var j = 0; j < arguments [i].length; j++) {
				set [arguments [i] [j]] = true;
			}
		}
		for (var i = 0; i < plus.length; i++) {
			if (! set [plus [i]])
				ret.push (plus [i]);
			set [plus [i]] = true;
		}
		return ret;
	},

	arrayUniq: function (arr) {
		var set = {}, ret = [];
		for (var i = 0; i < arr.length; i++) {
			if (set [arr [i]]) continue;
			set [arr [i]] = true;
			ret.push (arr [i]);
		}
		return ret;
	},

	formatCountry: function(country, region, city){
		var locationString = '';
		locationString = locationString + country;
		if(region){
			locationString = locationString + ', '+ region;
		}
		if(city){
			locationString = locationString + ', '+ city;
		}
		return locationString;
	},

	formatDate: function (dob) {
		splitDob = dob.split('-');
		var dob = new Date(splitDob[0], splitDob[1]-1, splitDob[2]);
		var today = new Date();
		var year = today.getFullYear();
		var roughAge = year - splitDob[0];
		today.setFullYear(splitDob[0]);
		if ((today-dob) < 0) roughAge -= 1;
		return roughAge;
	},

	ifUndef: function () {
		for (var i = 0; i < arguments.length; i++) {
			if (arguments [i] == undefined) continue;
			return arguments [i];
		}
		return undefined;
	},
	
	arrayMap: function (arr, fn) {
		var ret = new Array (arr.length);
		for (var i = 0; i < arr.length; i++) {
			ret [i] = fn (arr [i]);
		}
		return ret;
	},

	spliceArray: function (array, index, count, data) {
		var temp = array.slice (index + count);
		array.splice (index);
		array.concat (data, temp);
	}
};

 


var Jjax = jj.def ('Jjax', {

	integerRegex: /^(0|[123456789][0123456789]*)$/,

	

	Jjax: function () {
	},

	

	
	

	makeXmlHttpRequest: function () {
		if (window.XMLHttpRequest)
			return new XMLHttpRequest ();
		if (window.ActiveXObject)
			return new ActiveXObject ("Microsoft.XmlHttp");
		throw 'Unable to make XmlHttpRequest';
	},

	

	
	

	openXmlHttpRequest: function (req, a, b, c) {
		req.open (a, b, c);
	},

	

	
	
	
	
	
	
	
	

	simpleGet: function (url, handler, timeout) {
		var running = true;

		
		handler = jj.handlerFunc (handler, false);

		
		var request = this.makeXmlHttpRequest ();
	
		request.onreadystatechange = function () {

			
			if (! running) return;

			
			if (request.readyState != 4) return;

			
			var status = undefined;
			try { status = request.status; } catch (e) { }

			
			window.setTimeout (
				jj.bind (
					thisJjax,
					thisJjax.callHandler,
					handler,
					status == 200? 'onSuccess' : 'onFailure',
					[ request ]),
				0);

			
			running = false;
			delete request.onreadystatechange;
			delete request;
			delete handler;
		};

		
		this.openXmlHttpRequest (request, 'GET', url, true);
		request.send (null);

		
		if (timeout) setTimeout (function () {
			if (! running) return;

			
			request.abort ();

			
			handler ('onTimeout', [ request ]);

			
			running = false;
			delete request.onreadystatechange;
			delete request;
			delete handler;

		}, timeout);

		
		return {
			cancel: function () {
				if (! running) return;

				
				request.abort ();

				
				running = false;
				delete request.onreadystatechange;
				delete request;
				delete handler;
			}
		};

	},

	

	
	
	
	
	
	
	
	

	simplePost: function (url, contentType, body, handler, timeout) {
		var thisJjax = this;

		
		var running = true;

		
		handler = jj.handlerFunc (handler, false);

		
		var request = this.makeXmlHttpRequest ();

		request.onreadystatechange = function () {

			
			if (! running) return;

			
			if (request.readyState != 4) return;

			
			var status = undefined;
			try { status = request.status; } catch (e) { }

			
			window.setTimeout (
				jj.bind (
					thisJjax,
					thisJjax.callHandler,
					handler,
					status == 200? 'onSuccess' : 'onFailure',
					[ request ]),
				0);

			
			running = false;
			delete request.onreadystatechange;
			delete request;
			delete handler;
		};

		
		this.openXmlHttpRequest (request, 'POST', url, true);
		if (contentType)
			request.setRequestHeader ('Content-Type', contentType);
		request.send (body);

		
		if (timeout) setTimeout (function () {
			if (! running) return;
			
			
			request.abort ();

			
			thisJjax.callHandler (handler, 'onTimeout', [ request ]);
			
			
			running = false;
			delete request.onreadystatechange;
			delete request;
			delete handler;

		}, timeout);

		
		return {
			cancel: function () {

				
				if (! running) return;

				
				request.abort ();

				
				running = false;
				delete request.onreadystatechange;
				delete request;
				delete handler;
			}
		};
	},

	callHandler: function (handler, name, args) {
		var thisJjax = this;
		
			handler (name, args);
		
		
		
	},

	handlerException: function (name, args, exception) {
		if (flare.settings.version == 'trunk')	 alert ('Jjax caught exception in ' + name + ': ' + jj.errorSummary (exception));
	},

	toPhp: function (data) {
	
		if (data == undefined) {
			return 'N;';
		}
	
		if (typeof data == 'number') {
			if (! jj.isInt (data)) {
				return 'i:' + String (data) + ';';
			} else if (isNaN (data)) {
				return 'd:NAN;';
			} else {
				return 'd:' + String (data) + ';';
			}
		}
	
		if (typeof data == 'string') {
			return 's:' + jj.utfLen (data) + ':"' + data + '";';
		}
	
		if (typeof data == 'array' || data.constructor == Array) {
			var s = 'a:' + data.length + ':{';
			for (var i = 0; i < data.length; i++) {
				s += 'i:' + i + ';' + jjax.toPhp (data [i]);
			}
			return s + '}';
		}
	
		if (typeof data == 'object') {
			var keys = 0;
			for (var key in data) keys++;
			var s = 'a:' + keys + ':{';
			for (var key in data) {
				if ((typeof key == 'string' || key.constructor == String) && jjax.integerRegex.test (key))
					key = Number (key); 
				s += jjax.toPhp (key) + jjax.toPhp (data [key]);
			}
			return s + '}';
		}
	
		if (typeof data == 'boolean') {
			return 'b:' + (data? '1' : '0') + ';';
		}
	
		throw 'Don\'t know what to do with ' + typeof (data);
	},

	
	toJson: function (data) {
	
		if (data == undefined) {
			return 'undefined';
		}
	
		if (data == null) {
			return 'null';
		}

		if (typeof data == 'number') {
			return '' + data;
		}
	
		if (typeof data == 'string') {
			return '\'' + data
				.replace (/\u005c/g, '\\\\')
				.replace (/\u0027/g, '\\\'')
				.replace (/\u0000/g, '\\u0000')
				.replace (/\u0008/g, '\\b')
				.replace (/\u0009/g, '\\t')
				.replace (/\u000a/g, '\\n')
				.replace (/\u000b/g, '\\v')
				.replace (/\u000c/g, '\\f')
				.replace (/\u000d/g, '\\r')
				+ '\'';
		}
	
		if (typeof data == 'array' || data.constructor == Array) {
			var s = '[';
			var first = true;
			for (var i = 0; i < data.length; i++) {
				if (! first) s += ',';
				s += jjax.toJson (data [i]);
				first = false;
			}
			return s + ']';
		}

		if (typeof data == 'object') {
			var s = '{';
			var first = true;
			for (var key in data) {
				if (! first) s += ',';
				s += jjax.toJson (key) + ':' + jjax.toJson (data [key]);
				first = false;
			}
			return s + '}';
		}

		if (typeof data == 'boolean') {
			return data? 'true' : 'false';
		}
	
		throw 'Trying to encode ' + data;
	},

	fromJson: function (data) {
		try {
			return eval ('(' + data + ')');
		} catch (e) {
			throw 'Invalid JSON: ' + data;
		}
	}
});



var jjax = new Jjax ();

 


var beacon = {

	
	conv: {
	
		js: {
			contentType: 'text/javascript; charset=utf-8',
			encode: function (source) { return jjax.toJson (source); },
			decode: function (source) { return jjax.fromJson (source); }
		},
	
		php: {
			contentType: 'application/vnd.php.serialized; charset=utf-8',
			encode: function (source) { return jjax.toPhp (source); }
		}
	}
};

 



jj.mergeInto (beacon, {

	BeaconXhrClient: jj.def ('BeaconXhrClient', {

		BeaconXhrClient: function (url, convUp, convDown, timeout) {
			this.url = url;
			this.jjax = new Jjax ();
			this.convUp = convUp;
			this.convDown = convDown;
			this.timeout = timeout;
		},
	
		call: function (name, args, handlerAny) {
			return this.callFunc (name, args, jj.handlerFunc (handlerAny));
		},

		
		callFunc: function (name, args, handlerFunc) {
			var thisBeaconXhrClient = this;

			
			var req = {
				name: name,
				args: args };
			var reqStr = this.convUp.encode (req);

			
			var jjaxHandler = {

				onSuccess: function (xhr) {
					

						
						var resp;
						try {
							resp = thisBeaconXhrClient.convDown.decode (xhr.responseText);
						} catch (e) {
							
							handlerFunc ('failed', [ 'Unrecognised response from server: ' + xhr.responseText ]);
							return;
						}

						
						if ('debug' in resp)
							for (var i in resp.debug)
								alert ('Beacon debug: ' + resp.debug [i]);

						
						
							handlerFunc (resp.name, resp.args);
						
						
						
						
						

					
					
					
				},

				onFailure: function (xhr) {
					handlerFunc ('failed', [ 'HTTP request failed with status ' + xhr.status ]);
				},

				onTimeout: function (xhr) {
					handlerFunc ('timeout', [ 'HTTP request timed out' ]);
				}
			};

			
			this.jjax.simplePost (this.url, this.convUp.contentType, reqStr, jjaxHandler, this.timeout);
		},
		
		onHandlerError: function (e) {
		if (flare.settings.version == 'trunk')	 alert ('Beacon caught exception in response handler: ' + jj.errorSummary (e));
		}
	})
});

 


jj.mergeInto (beacon, {	

	makeXhrClient: function (url, conv) {
	
		
		if (! conv) conv = 'js';
		var temp = conv.split ('/');
		var from = conv, to = conv;
		if (temp.length == 2) {
			from = temp [0];
			to = temp [1];
		}
		
		if (! (from in beacon.conv) || ! ('encode' in beacon.conv [from]))
			throw 'Unsupported request format: ' + from;
		if (! (to in beacon.conv) || ! ('decode' in beacon.conv [to]))
			throw 'Unsupported response format: ' + to;

		
		return new beacon.BeaconXhrClient (url, beacon.conv [from], beacon.conv [to]);
	}
});

 


var md5 = {

	
	hash: function (x, len) {

		
		x [len >> 5] |= 0x80 << ((len) % 32);
		x [(((len + 64) >>> 9) << 4) + 14] = len;
	
		var a =  1732584193;
		var b = -271733879;
		var c = -1732584194;
		var d =  271733878;
	
		for (var i = 0; i < x.length; i += 16) {
			var olda = a;
			var oldb = b;
			var oldc = c;
			var oldd = d;
	
			a = md5.ff (a, b, c, d, x [i+ 0], 7 , -680876936);
			d = md5.ff (d, a, b, c, x [i+ 1], 12, -389564586);
			c = md5.ff (c, d, a, b, x [i+ 2], 17,  606105819);
			b = md5.ff (b, c, d, a, x [i+ 3], 22, -1044525330);
			a = md5.ff (a, b, c, d, x [i+ 4], 7 , -176418897);
			d = md5.ff (d, a, b, c, x [i+ 5], 12,  1200080426);
			c = md5.ff (c, d, a, b, x [i+ 6], 17, -1473231341);
			b = md5.ff (b, c, d, a, x [i+ 7], 22, -45705983);
			a = md5.ff (a, b, c, d, x [i+ 8], 7 ,  1770035416);
			d = md5.ff (d, a, b, c, x [i+ 9], 12, -1958414417);
			c = md5.ff (c, d, a, b, x [i+10], 17, -42063);
			b = md5.ff (b, c, d, a, x [i+11], 22, -1990404162);
			a = md5.ff (a, b, c, d, x [i+12], 7 ,  1804603682);
			d = md5.ff (d, a, b, c, x [i+13], 12, -40341101);
			c = md5.ff (c, d, a, b, x [i+14], 17, -1502002290);
			b = md5.ff (b, c, d, a, x [i+15], 22,  1236535329);
		
			a = md5.gg (a, b, c, d, x [i+ 1], 5 , -165796510);
			d = md5.gg (d, a, b, c, x [i+ 6], 9 , -1069501632);
			c = md5.gg (c, d, a, b, x [i+11], 14,  643717713);
			b = md5.gg (b, c, d, a, x [i+ 0], 20, -373897302);
			a = md5.gg (a, b, c, d, x [i+ 5], 5 , -701558691);
			d = md5.gg (d, a, b, c, x [i+10], 9 ,  38016083);
			c = md5.gg (c, d, a, b, x [i+15], 14, -660478335);
			b = md5.gg (b, c, d, a, x [i+ 4], 20, -405537848);
			a = md5.gg (a, b, c, d, x [i+ 9], 5 ,  568446438);
			d = md5.gg (d, a, b, c, x [i+14], 9 , -1019803690);
			c = md5.gg (c, d, a, b, x [i+ 3], 14, -187363961);
			b = md5.gg (b, c, d, a, x [i+ 8], 20,  1163531501);
			a = md5.gg (a, b, c, d, x [i+13], 5 , -1444681467);
			d = md5.gg (d, a, b, c, x [i+ 2], 9 , -51403784);
			c = md5.gg (c, d, a, b, x [i+ 7], 14,  1735328473);
			b = md5.gg (b, c, d, a, x [i+12], 20, -1926607734);
		
			a = md5.hh (a, b, c, d, x [i+ 5], 4 , -378558);
			d = md5.hh (d, a, b, c, x [i+ 8], 11, -2022574463);
			c = md5.hh (c, d, a, b, x [i+11], 16,  1839030562);
			b = md5.hh (b, c, d, a, x [i+14], 23, -35309556);
			a = md5.hh (a, b, c, d, x [i+ 1], 4 , -1530992060);
			d = md5.hh (d, a, b, c, x [i+ 4], 11,  1272893353);
			c = md5.hh (c, d, a, b, x [i+ 7], 16, -155497632);
			b = md5.hh (b, c, d, a, x [i+10], 23, -1094730640);
			a = md5.hh (a, b, c, d, x [i+13], 4 ,  681279174);
			d = md5.hh (d, a, b, c, x [i+ 0], 11, -358537222);
			c = md5.hh (c, d, a, b, x [i+ 3], 16, -722521979);
			b = md5.hh (b, c, d, a, x [i+ 6], 23,  76029189);
			a = md5.hh (a, b, c, d, x [i+ 9], 4 , -640364487);
			d = md5.hh (d, a, b, c, x [i+12], 11, -421815835);
			c = md5.hh (c, d, a, b, x [i+15], 16,  530742520);
			b = md5.hh (b, c, d, a, x [i+ 2], 23, -995338651);
		
			a = md5.ii (a, b, c, d, x [i+ 0], 6 , -198630844);
			d = md5.ii (d, a, b, c, x [i+ 7], 10,  1126891415);
			c = md5.ii (c, d, a, b, x [i+14], 15, -1416354905);
			b = md5.ii (b, c, d, a, x [i+ 5], 21, -57434055);
			a = md5.ii (a, b, c, d, x [i+12], 6 ,  1700485571);
			d = md5.ii (d, a, b, c, x [i+ 3], 10, -1894986606);
			c = md5.ii (c, d, a, b, x [i+10], 15, -1051523);
			b = md5.ii (b, c, d, a, x [i+ 1], 21, -2054922799);
			a = md5.ii (a, b, c, d, x [i+ 8], 6 ,  1873313359);
			d = md5.ii (d, a, b, c, x [i+15], 10, -30611744);
			c = md5.ii (c, d, a, b, x [i+ 6], 15, -1560198380);
			b = md5.ii (b, c, d, a, x [i+13], 21,  1309151649);
			a = md5.ii (a, b, c, d, x [i+ 4], 6 , -145523070);
			d = md5.ii (d, a, b, c, x [i+11], 10, -1120210379);
			c = md5.ii (c, d, a, b, x [i+ 2], 15,  718787259);
			b = md5.ii (b, c, d, a, x [i+ 9], 21, -343485551);
		
			a = md5.safeAdd (a, olda);
			b = md5.safeAdd (b, oldb);
			c = md5.safeAdd (c, oldc);
			d = md5.safeAdd (d, oldd);
		}
		return Array (a, b, c, d);
	},
	
	
	cmn: function (q, a, b, x, s, t) {
		return md5.safeAdd (md5.bitRol (md5.safeAdd (md5.safeAdd (a, q), md5.safeAdd (x, t)), s), b);
	},

	ff: function (a, b, c, d, x, s, t) {
		return md5.cmn ((b & c) | ((~b) & d), a, b, x, s, t);
	},

	gg: function (a, b, c, d, x, s, t) {
		return md5.cmn((b & d) | (c & (~d)), a, b, x, s, t);
	},
	
	hh: function (a, b, c, d, x, s, t) {
		return md5.cmn (b ^ c ^ d, a, b, x, s, t);
	},

	ii: function (a, b, c, d, x, s, t) {
		return md5.cmn (c ^ (b | (~d)), a, b, x, s, t);
	},

	
	hmac: function (bkey, data) {
		if (bkey.length > 16) bkey = core_md5 (bkey, key.length * 8);
	
		var ipad = Array (16), opad = Array (16);
		for (var i = 0; i < 16; i++) {
			ipad [i] = bkey [i] ^ 0x36363636;
			opad [i] = bkey [i] ^ 0x5C5C5C5C;
		}
	
		var hash = md5.hash (ipad.concat (data), 512 + data.length * 8);
		return md5.hash (opad.concat (hash), 512 + 128);
	},
	
	
	safeAdd: function (x, y) {
		var lsw = (x & 0xFFFF) + (y & 0xFFFF);
		var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
		return (msw << 16) | (lsw & 0xFFFF);
	},
	
	
	bitRol: function (num, cnt) {
		return (num << cnt) | (num >>> (32 - cnt));
	},

	
	str2binl: function (str, chrsz) {
		var bin = Array ();
		var mask = (1 << chrsz) - 1;
		for (var i = 0; i < str.length * chrsz; i += chrsz)
			bin [i>>5] |= (str.charCodeAt (i / chrsz) & mask) << (i%32);
		return bin;
	},
	
	
	binl2str: function (bin, chrsz) {
		var str = "";
		var mask = (1 << chrsz) - 1;
		for (var i = 0; i < bin.length * 32; i += chrsz)
			str += String.fromCharCode ((bin [i>>5] >>> (i % 32)) & mask);
		return str;
	},
	
	
	binl2hex: function (binarray) {
		var hexTab = "0123456789abcdef";
		var str = "";
		for (var i = 0; i < binarray.length * 4; i++) {
			str += hexTab.charAt ((binarray [i>>2] >> ((i%4)*8+4)) & 0xF)
				+ hexTab.charAt ((binarray [i>>2] >> ((i%4)*8  )) & 0xF);
		}
		return str;
	},
	
	
	binl2b64: function (binarray) {
		var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
		var str = "";
		for (var i = 0; i < binarray.length * 4; i += 3) {
			var triplet = (((binarray [i >> 2] >> 8 * (i % 4)) & 0xFF) << 16)
				| (((binarray [i + 1 >> 2] >> 8 * ((i + 1) % 4)) & 0xFF) << 8)
				| ((binarray [i + 2 >> 2] >> 8 * ((i + 2) % 4)) & 0xFF);
			for (var j = 0; j < 4; j++) {
				if (i * 8 + j * 6 > binarray.length * 32) str += '=';
				else str += tab.charAt ((triplet >> 6 * (3 - j)) & 0x3F);
			}
		}
		return str;
	}
};


 


var utf8 = {

	
	encode: function (str) {
		var s = "";

		for (var i = 0; i < str.length; i++) {

			var c = str.charCodeAt (i);

			if (c < 128) {
				s += String.fromCharCode (c);
			}
			else if ((c > 127) && (c < 2048)) {
				s += String.fromCharCode ((c >> 6) | 192);
				s += String.fromCharCode ((c & 63) | 128);
			} else {
				s += String.fromCharCode ((c >> 12) | 224);
				s += String.fromCharCode (((c >> 6) & 63) | 128);
				s += String.fromCharCode ((c & 63) | 128);
			}
		}

		return s;
	},

	
	decode: function (utftext) {
		var s = "";
		var i = 0;
		var c, c1, c2;

		for (var i = 0; i < utftext.length; i++) {

			c = utftext.charCodeAt(i);

			if (c < 128) {
				s += String.fromCharCode(c);
			} else if ((c > 191) && (c < 224)) {
				c2 = utftext.charCodeAt (i+1);
				s += String.fromCharCode (((c & 31) << 6) | (c2 & 63));
				i++;
			} else {
				c2 = utftext.charCodeAt (i+1);
				c3 = utftext.charCodeAt (i+2);
				s += String.fromCharCode (((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 2;
			}
		}

		return s;
	}
};

 




 

