PageSourceSearch

https://museum-kai.net/alib_ajax_server.php?client=all

js museum-kai.net collected 2026-10-08 04:15:46 UTC 88,881 bytes, 3,130 lines download raw bytes

1// Compat.js
2/**
3 * Compat functions
4 * @category	HTML
5 * @package	AJAX
6 * @author	Joshua Eichorn <[email protected]>
7 * @copyright	2005 Joshua Eichorn
8 * @license	http://www.opensource.org/licenses/lgpl-license.php  LGPL
9 */
10/**
11 *  Functions for compatibility with older browsers
12 */
13if (!String.fromCharCode && !String.prototype.fromCharCode) {
14	String.prototype.fromCharCode = function(code)
15	{
16		var h = code.toString(16);
17		if (h.length == 1) {
18			h = '0' + h;
19		}
20		return unescape('%' + h);
21	}
22}
23if (!String.charCodeAt && !String.prototype.charCodeAt) {
24	String.prototype.charCodeAt = function(index)
25	{
26		var c = this.charAt(index);
27		for (i = 1; i < 256; i++) {
28			if (String.fromCharCode(i) == c) {
29				return i;
30			}
31		} 
32	}
33}
34// http://www.crockford.com/javascript/remedial.html
35if (!Array.splice && !Array.prototype.splice) {
36	Array.prototype.splice = function(s, d)
37	{
38		var max = Math.max,
39		min = Math.min,
40		a = [], // The return value array
41		e,  // element
42		i = max(arguments.length - 2, 0),   // insert count
43		k = 0,
44		l = this.length,
45		n,  // new length
46		v,  // delta
47		x;  // shift count
48
49		s = s || 0;
50		if (s < 0) {
51			s += l;
52		}
53		s = max(min(s, l), 0);  // start point
54		d = max(min(typeof d == 'number' ? d : l, l - s), 0);	// delete count
55		v = i - d;
56		n = l + v;
57		while (k < d) {
58			e = this[s + k];
59			if (!e) {
60				a[k] = e;
61			}
62			k += 1;
63		}
64		x = l - s - d;
65		if (v < 0) {
66			k = s + i;
67			while (x) {
68				this[k] = this[k - v];
69				k += 1;
70				x -= 1;
71			}
72			this.length = n;
73		} else if (v > 0) {
74			k = 1;
75			while (x) {
76				this[n - k] = this[l - k];
77				k += 1;
78				x -= 1;
79			}
80		}
81		for (k = 0; k < i; ++k) {
82			this[s + k] = arguments[k + 2];
83		}
84		return a;
85	}
86}
87if (!Array.push && !Array.prototype.push) {
88	Array.prototype.push = function()
89	{
90		for (var i = 0, startLength = this.length; i < arguments.length; i++) {
91			this[startLength + i] = arguments[i];
92		}
93		return this.length;
94	}
95}
96if (!Array.pop && !Array.prototype.pop) {
97	Array.prototype.pop = function()
98	{
99		return this.splice(this.length - 1, 1)[0];
100	}
101}
102if (window.ActiveXObject && window['DOMParser'] == 'undefined') {
103	window.DOMParser = new function() {};
104	DOMParser.prototype = {
105		parseFromString: function(str, contentType) {
106			var xmlDocument = new ActiveXObject('Microsoft.XMLDOM');
107			xmlDocument.loadXML(str);
108			return xmlDocument;
109		}
110	};
111
112	window.XMLSerializer = new function() {};
113	XMLSerializer.prototype = {
114		serializeToString: function(root) {
115			return root.xml || root.outerHTML;
116		}
117	};
118}
119// Main.js
120/**
121 * JavaScript library for use with HTML_AJAX
122 *
123 * This library is free software; you can redistribute it and/or
124 * modify it under the terms of the GNU Lesser General Public
125 * License as published by the Free Software Foundation; either
126 * version 2.1 of the License, or (at your option) any later version.
127 *
128 * This library is distributed in the hope that it will be useful,
129 * but WITHOUT ANY WARRANTY; without even the implied warranty of
130 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
131 * Lesser General Public License for more details.
132 *
133 * You should have received a copy of the GNU Lesser General Public
134 * License along with this library; if not, write to:
135 * Free Software Foundation, Inc.,
136 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
137 *
138 * @category	HTML
139 * @package	Ajax
140 * @author	Joshua Eichorn <[email protected]>
141 * @author	Arpad Ray <[email protected]>
142 * @author	David Coallier <[email protected]>
143 * @author	Elizabeth Smith <[email protected]>
144 * @copyright	2005 Joshua Eichorn, Arpad Ray, David Coallier, Elizabeth Smith
145 * @license	http://www.opensource.org/licenses/lgpl-license.php  LGPL
146 */
147
148/**
149 * HTML_AJAX static methods, this is the main proxyless api, it also handles global error and event handling
150 */
151var HTML_AJAX = {
152	version: '0.5.6',
153	defaultServerUrl: false,
154	defaultEncoding: 'JSON',
155	queues: false,
156	clientPools: {},
157	// get an HttpClient, supply a name to use the pool of that name or the default if it isn't found
158	httpClient: function(name) {
159		if (name) {
160			if (this.clientPools[name]) {
161				return this.clientPools[name].getClient();
162			}
163		}
164		return this.clientPools['default'].getClient();
165	},
166	// Pushing the given request to queue specified by it, in default operation this will immediately make a request
167	// request might be delayed or never happen depending on the queue setup
168	// making a sync request to a non immediate queue will cause you problems so just don't do it
169	makeRequest: function(request) {
170		if (!HTML_AJAX.queues[request.queue]) {
171			var e = new Error('Unknown Queue: '+request.queue);
172			if (HTML_AJAX.onError) {
173				HTML_AJAX.onError(e);
174				return false;
175			}
176			else {
177				throw(e);
178			}
179		}
180		else {
181			var qn = request.queue;
182			var q = HTML_AJAX.queues[qn];
183
184			HTML_AJAX.queues[request.queue].addRequest(request);
185			return HTML_AJAX.queues[request.queue].processRequest();
186		}
187	},
188	// get a serializer object for a specific encoding
189	serializerForEncoding: function(encoding) {
190		for(var i in HTML_AJAX.contentTypeMap) {
191			if (encoding == HTML_AJAX.contentTypeMap[i] || encoding == i) {
192				return eval("new HTML_AJAX_Serialize_"+i+";");
193			}
194		}
195		return new HTML_AJAX_Serialize_Null();
196	},
197	fullcall: function(url,encoding,className,method,callback,args, options) {
198		var serializer = HTML_AJAX.serializerForEncoding(encoding);
199
200		var request = new HTML_AJAX_Request(serializer);
201		if (callback) {
202			request.isAsync = true;
203		}
204		request.requestUrl = url;
205		request.className = className;
206		request.methodName = method;
207		request.callback = callback;
208		request.args = args;
209		if (options) {
210			for(var i in options) {
211				request[i] = options[i];
212			}
213			if (options.grab) {
214				if (!request.args || !request.args.length) {
215					request.requestType = 'GET';
216				}
217			}
218		}
219
220		return HTML_AJAX.makeRequest(request);
221	},
222	callPhpCallback: function(phpCallback, jsCallback, url) {
223		var args = new Array();
224		for (var i = 3; i < arguments.length; i++) {
225			args.push(arguments[i]);
226		}
227		if (HTML_AJAX_Util.getType(phpCallback[0]) == 'object') {
228			jsCallback(phpCallback[0][phpCallback[1]](args));
229			return;
230		}
231		if (!url) {
232			url = HTML_AJAX.defaultServerUrl;
233		}
234		HTML_AJAX.fullcall(url, HTML_AJAX.defaultEncoding,
235			false, false, jsCallback, args, {phpCallback: phpCallback});
236	},
237	call: function(className,method,callback) {
238		var args = new Array();
239		for(var i = 3; i < arguments.length; i++) {
240			args.push(arguments[i]);
241		}
242		return HTML_AJAX.fullcall(HTML_AJAX.defaultServerUrl,HTML_AJAX.defaultEncoding,className,method,callback,args);
243	},
244	grab: function(url,callback,options) {
245		if (!options) {
246			options = {grab:true};
247		}
248		else {
249			options['grab'] = true;
250		}
251		return HTML_AJAX.fullcall(url,'Null',false,null,callback, '', options);
252	},
253	post: function(url,payload,callback,options) {
254		var serializer = 'Null';
255		if (HTML_AJAX_Util.getType(payload) == 'object') {
256			serializer = 'Urlencoded';
257		}
258		return HTML_AJAX.fullcall(url,serializer,false,null,callback, payload, options);
259	},
260	replace: function(id) {
261		var callback = function(result) {
262			HTML_AJAX_Util.setInnerHTML(HTML_AJAX_Util.getElement(id),result);
263		}
264		if (arguments.length == 2) {
265			// grab replacement
266			HTML_AJAX.grab(arguments[1],callback);
267		}
268		else {
269			// call replacement
270			var args = new Array();
271			for(var i = 3; i < arguments.length; i++) {
272				args.push(arguments[i]);
273			}
274			HTML_AJAX.fullcall(HTML_AJAX.defaultServerUrl,HTML_AJAX.defaultEncoding,arguments[1],arguments[2],callback,args, {grab:true});
275		}
276	},
277	append: function(id) {
278		var callback = function(result) {
279			HTML_AJAX_Util.setInnerHTML(HTML_AJAX_Util.getElement(id),result,'append');
280		}
281		if (arguments.length == 2) {
282			// grab replacement
283			HTML_AJAX.grab(arguments[1],callback);
284		}
285		else {
286			// call replacement
287			var args = new Array();
288			for(var i = 3; i < arguments.length; i++) {
289				args.push(arguments[i]);
290			}
291			HTML_AJAX.fullcall(HTML_AJAX.defaultServerUrl,HTML_AJAX.defaultEncoding,arguments[1],arguments[2],callback,args, {grab:true});
292		}
293	}, 
294	// override to add top level loading notification (start)
295	Open: function(request) {
296	},
297	// override to add top level loading notification (finish)
298	Load: function(request) {
299	},
300	/*
301	// A really basic error handler 
302	onError: function(e) {
303		msg = "";
304		for(var i in e) {
305			msg += i+':'+e[i]+"\n";
306		}
307		alert(msg);
308	},
309	*/
310	// Class postfix to content-type map
311	contentTypeMap: {
312		'JSON':			'application/json',
313		'Null':			'text/plain',
314		'Error':		'application/error',
315		'PHP':			'application/php-serialized',
316		'HA' :			'application/html_ajax_action',
317		'Urlencoded':		'application/x-www-form-urlencoded'
318	},
319	// used internally to make queues work, override Load or onError to perform custom events when a request is complete
320	// fires on success and error
321	requestComplete: function(request,error) {
322		for(var i in HTML_AJAX.queues) {
323			if (HTML_AJAX.queues[i].requestComplete) {
324				HTML_AJAX.queues[i].requestComplete(request,error);
325			}
326		}
327	},
328	
329	// turns a form into a urlencoded string
330	formEncode: function(form, array_format) {
331		form = HTML_AJAX_Util.getElement(form);
332		var el, inpType, value, name;
333		var out = (array_format) ? {} : '';
334		var inputTags = form.getElementsByTagName('INPUT');
335		var selectTags = form.getElementsByTagName('SELECT');
336		var buttonTags = form.getElementsByTagName('BUTTON');
337		var textareaTags = form.getElementsByTagName('TEXTAREA');
338		var arrayRegex = /(.+)%5B%5D/;
339
340		var validElement = function (element) {
341			if (!element || !element.getAttribute) {
342				return false;
343			}
344			el = element;
345			name = HTML_AJAX_Util.encodeUrl(el.getAttribute('name'));
346			if (!name) {
347				// no element name so skip
348				return false;
349			}
350			if (element.disabled) {
351				return false;
352			}
353			
354			if (!array_format) {
355				value = HTML_AJAX_Util.encodeUrl(el.value);
356			} else {
357				value = el.value;
358			}
359			
360			inpType = el.getAttribute('type');
361			return true;
362		}
363		
364		inputLoop:
365		for (var i=0; i < inputTags.length; i++) {
366			if (!validElement(inputTags[i])) {
367				continue;
368			}
369			if (inpType == 'checkbox' || inpType == 'radio') {
370				if (!el.checked) {
371					// unchecked radios/checkboxes don't get submitted
372					continue inputLoop;
373				}
374				var arr_var = arrayRegex.exec(name); 
375				if (array_format && arr_var) {
376					if (!out[arr_var[1]]) {
377						out[arr_var[1]] = new Array();
378					}
379					out[arr_var[1]].push(value);
380					continue inputLoop;
381				}
382			}
383			// add element to output array
384			if (array_format) {
385				out[name] = value;
386			} else {
387				out += name + '=' + value + '&';
388			}
389		} // end inputLoop
390
391		selectLoop:
392		for (var i=0; i<selectTags.length; i++) {
393			if (!validElement(selectTags[i])) {
394				continue selectLoop;
395			}
396			var options = el.options;
397			for (var z=0; z<options.length; z++){
398				var option=options[z];
399				if(option.selected){
400					if (array_format) {
401						if (el.type == 'select-one') {
402							out[name] = option.value;
403							//only one item can be selected
404							continue selectLoop;
405						} else {
406							if (!out[name]) {
407								out[name] = new Array();
408							}
409							out[name].push(option.value);
410						}
411					} else {
412						out += name + '=' + option.value + '&';
413						if (el.type == 'select-one') {
414							continue selectLoop;
415						}
416					}
417				}
418			}
419		} // end selectLoop
420
421		buttonLoop:
422		for (var i=0; i<buttonTags.length; i++) {
423			if (!validElement(buttonTags[i])) {
424				continue;
425			}
426			// add element to output array
427			if (array_format) {
428				out[name] = value;
429			} else {
430				out += name + '=' + value + '&';
431			}
432		} // end buttonLoop
433
434		textareaLoop:
435		for (var i=0; i<textareaTags.length; i++) {
436			if (!validElement(textareaTags[i])) {
437				continue;
438			}
439			// add element to output array
440			if (array_format) {
441				out[name] = value;
442			} else {
443				out += name + '=' + value + '&';
444			}
445		} // end textareaLoop
446		
447		return out;
448	},
449	// submits a form through ajax. both arguments can be either DOM nodes or IDs, if the target is omitted then the form is set to be the target
450	formSubmit: function (form, target, options)
451	{
452		form = HTML_AJAX_Util.getElement(form);
453		if (!form) {
454		// let the submit be processed normally
455			return false;
456		}
457
458		var out = HTML_AJAX.formEncode(form);
459		target = HTML_AJAX_Util.getElement(target);
460		if (!target) {
461			target = form;
462		}
463		try
464		{
465			var action = form.attributes['action'].value;
466		}
467		catch(e){}
468		if(action == undefined)
469		{
470			action = form.getAttribute('action');
471		}
472
473		var callback = false;
474		if (HTML_AJAX_Util.getType(target) == 'function') {
475			callback = target;
476		}
477		else {
478			callback = function(result) {
479				// result will be undefined if HA_Action is returned, so skip the replace
480				if (typeof result != 'undefined') {
481					HTML_AJAX_Util.setInnerHTML(target,result);
482				}
483			}
484		}
485
486		var serializer = HTML_AJAX.serializerForEncoding('Null');
487		var request = new HTML_AJAX_Request(serializer);
488		request.isAsync = true;
489		request.callback = callback;
490
491		switch (form.getAttribute('method').toLowerCase()) {
492		case 'post':
493			var headers = {};
494			headers['Content-Type'] = 'application/x-www-form-urlencoded';
495			request.customHeaders = headers;
496			request.requestType = 'POST';
497			request.requestUrl = action;
498			request.args = out;
499			break;
500		default:
501			if (action.indexOf('?') == -1) {
502				out = '?' + out.substr(0, out.length - 1);
503			}
504			request.requestUrl = action+out;
505			request.requestType = 'GET';
506		}
507
508		if(options) {
509			for(var i in options) {
510				request[i] = options[i];
511			}
512		}
513
514		if (request.isAsync == false) {
515			return HTML_AJAX.makeRequest(request);
516		}
517		else {
518			HTML_AJAX.makeRequest(request);
519			return true;
520		}
521	}, // end formSubmit()
522	makeFormAJAX: function(form,target,options) {
523		form = HTML_AJAX_Util.getElement(form);
524		var preSubmit = false;
525		if(typeof form.onsubmit != 'undefined') {
526			preSubmit = form.onsubmit;
527			form.onsubmit = function() {};
528		}
529		form.HAOptions = options;
530		var handler = function(e) {
531			var form = HTML_AJAX_Util.eventTarget(e);
532
533			var valid = true;
534			if (preSubmit) {
535				valid = preSubmit();
536			}
537			if (valid) {
538				HTML_AJAX.formSubmit(form,target,form.HAOptions);
539			}
540			// cancel submission in IE
541			e.returnValue = false;
542			// cancel submission in FF
543			if (e.preventDefault) {
544				e.preventDefault();
545			}
546		}
547		HTML_AJAX_Util.registerEvent(form,'submit',handler);
548	}
549}
550
551
552
553
554// small classes that I don't want to put in there own file
555
556function HTML_AJAX_Serialize_Null() {}
557HTML_AJAX_Serialize_Null.prototype = {
558	contentType: 'text/plain; charset=utf-8',
559	serialize: function(input) {
560		return new String(input).valueOf();
561	},
562	
563	unserialize: function(input) {
564		return new String(input).valueOf();	
565	}
566}
567
568function HTML_AJAX_Serialize_XML() {}
569HTML_AJAX_Serialize_XML.prototype = {
570	contentType: 'application/xml; charset=utf-8',
571	serialize: function(input) {
572		var xml = '';
573		if(typeof(input) == 'object' && input)
574		{
575			for (var i = 0;i<input.length;i++)
576			{
577				xml += new XMLSerializer().serializeToString(input[i]);
578			}
579		}
580		return xml;
581	},
582
583	unserialize: function(input) {
584		return input;
585	}
586}
587
588// serialization class for JSON, wrapper for JSON.stringify in json.js
589function HTML_AJAX_Serialize_JSON() {}
590HTML_AJAX_Serialize_JSON.prototype = {
591	contentType: 'application/json; charset=utf-8',
592	serialize: function(input) {
593		return HTML_AJAX_JSON.stringify(input);
594	},
595	unserialize: function(input) {
596		try {
597			return eval('('+input+')');
598		} catch(e) {
599			// sometimes JSON encoded input isn't created properly, if eval of it fails we use the more forgiving but slower parser so will at least get something
600			return HTML_AJAX_JSON.parse(input);
601		}
602	}
603}
604
605function HTML_AJAX_Serialize_Error() {}
606HTML_AJAX_Serialize_Error.prototype = {
607	contentType: 'application/error; charset=utf-8',
608	serialize: function(input) {
609		var ser = new HTML_AJAX_Serialize_JSON();
610		return ser.serialize(input);
611	},
612	unserialize: function(input) {
613		var ser = new HTML_AJAX_Serialize_JSON();
614		var data = new ser.unserialize(input);
615
616		var e = new Error('PHP Error: '+data.errStr);
617		for(var i in data) {
618			e[i] = data[i];
619		}
620		throw e;
621	}
622}
623
624// Processing Queues
625
626// simple queue, just processes the request immediately
627function HTML_AJAX_Queue_Immediate() {}
628HTML_AJAX_Queue_Immediate.prototype = {
629	request: false,
630	addRequest: function(request) {
631		this.request = request;
632	},
633	processRequest: function() {
634		var client = HTML_AJAX.httpClient();
635		client.request = this.request;
636		return client.makeRequest();
637	}
638}
639
640
641
642// create a default queue, has to happen after the Queue class has been defined
643HTML_AJAX.queues = new Object();
644HTML_AJAX.queues['default'] = new HTML_AJAX_Queue_Immediate();
645
646// Queue.js
647/**
648 * Various processing queues, use when you want to control how multiple requests are made
649 * @category	HTML
650 * @package	AJAX
651 * @author	Joshua Eichorn <[email protected]>
652 * @copyright	2005 Joshua Eichorn
653 * @license	http://www.opensource.org/licenses/lgpl-license.php  LGPL
654 */
655
656// Single Buffer queue with interval
657// works by attempting to send a request every x miliseconds
658// if an item is currently in the queue when a new item is added it will be replaced
659// simple queue, just processes the request immediately
660// the first request starts the interval timer
661function HTML_AJAX_Queue_Interval_SingleBuffer(interval,singleOutstandingRequest) {
662	this.interval = interval;
663	if (singleOutstandingRequest) {
664		this.singleOutstandingRequest = true;
665	}
666}
667HTML_AJAX_Queue_Interval_SingleBuffer.prototype = {
668	request: false,
669	_intervalId: false,
670	singleOutstandingRequest: false,
671	client: false,
672	addRequest: function(request) {
673		this.request = request;
674	},
675	processRequest: function() {
676		if (!this._intervalId) {
677			this.runInterval();
678			this.start();
679		}
680	}, 
681	start: function() {
682		var self = this;
683		this._intervalId = setInterval(function() { self.runInterval() },this.interval);
684	},
685	stop: function() {
686		clearInterval(this._intervalId);
687	},
688	runInterval: function() {
689		if (this.request) {
690			if (this.singleOutstandingRequest && this.client) {
691				this.client.abort();
692			}
693			this.client = HTML_AJAX.httpClient();
694			this.client.request = this.request;
695			this.request = false;
696			this.client.makeRequest();
697		}
698	}
699}
700
701// Requests return in the same order they were called
702// this helps handle high latency situations
703function HTML_AJAX_Queue_Ordered() { }
704HTML_AJAX_Queue_Ordered.prototype = {
705	request: false,
706	order: 0,
707	current: 0,
708	callbacks: {},
709	interned: {},
710	addRequest: function(request) {
711		request.order = this.order;
712		this.request = request;
713		this.callbacks[this.order] = this.request.callback;
714		var self = this;
715		this.request.callback = function(result) {
716			self.processCallback(result,request.order);
717		} 
718	},
719	processRequest: function() {
720		var client = HTML_AJAX.httpClient();
721		client.request = this.request;
722		client.makeRequest();
723		this.order++;
724	},
725	requestComplete: function(request,e) {
726		// something when wrong with the request lets stop waiting for it
727		if (e) {
728			this.current++;
729		}
730	},
731	processCallback: function(result,order) {
732		if (order == this.current) {
733			this.callbacks[order](result);
734			this.current++;
735		}
736		else {
737			this.interned[order] = result;
738		}
739		while (this.interned[this.current]) {
740			this.callbacks[this.current](this.interned[this.current]);
741			this.current++;
742		}
743}
744}
745
746// Make a single request at once, canceling and currently outstanding requests when a new one is made
747function HTML_AJAX_Queue_Single() {
748}
749HTML_AJAX_Queue_Single.prototype = {
750	request: false,
751	client: false,
752	addRequest: function(request) {
753		this.request = request;
754	},
755	processRequest: function() {
756		if (this.request) {
757			if (this.client) {
758				this.client.abort();
759			}
760			this.client = HTML_AJAX.httpClient();
761			this.client.request = this.request;
762			this.request = false;
763			this.client.makeRequest();
764		}
765	}
766}
767
768/**
769 * Priority queue
770 *
771 * @author	 Arpad Ray <[email protected]>
772 */
773function HTML_AJAX_Queue_Priority_Item(item, time) {
774	this.item = item;
775	this.time = time;
776}
777HTML_AJAX_Queue_Priority_Item.prototype = {
778	compareTo: function (other) {
779		var ret = this.item.compareTo(other.item);
780		if (ret == 0) {
781			ret = this.time - other.time;
782		}
783		return ret;
784	}
785}
786
787function HTML_AJAX_Queue_Priority_Simple(interval) {
788	this.interval = interval;   
789	this.idleMax = 10;			// keep the interval going with an empty queue for 10 intervals
790	this.requestTimeout = 5;	  // retry uncompleted requests after 5 seconds
791	this.checkRetryChance = 0.1;  // check for uncompleted requests to retry on 10% of intervals
792	this._intervalId = 0;
793	this._requests = [];
794	this._removed = [];
795	this._len = 0;
796	this._removedLen = 0;
797	this._idle = 0;
798}
799HTML_AJAX_Queue_Priority_Simple.prototype = {
800	isEmpty: function () {
801		return this._len == 0;
802	},
803	addRequest: function (request) {
804		request = new HTML_AJAX_Queue_Priority_Item(request, new Date().getTime());
805		++this._len;
806		if (this.isEmpty()) {
807			this._requests[0] = request;
808			return;
809		}
810		for (i = 0; i < this._len - 1; i++) {
811			if (request.compareTo(this._requests[i]) < 0) {
812				this._requests.splice(i, 1, request, this._requests[i]);
813				return;
814			}
815		}
816		this._requests.push(request);
817	},
818	peek: function () {
819		return (this.isEmpty() ? false : this._requests[0]);
820	},
821	requestComplete: function (request) {
822		for (i = 0; i < this._removedLen; i++) {
823			if (this._removed[i].item == request) {
824				this._removed.splice(i, 1);
825				--this._removedLen;
826				out('removed from _removed');
827				return true;
828			}
829		}
830		return false;
831	},
832	processRequest: function() {
833		if (!this._intervalId) {
834			this._runInterval();
835			this._start();
836		}
837		this._idle = 0;
838	},
839	_runInterval: function() {
840		if (Math.random() < this.checkRetryChance) {
841			this._doRetries();
842		}
843		if (this.isEmpty()) {
844			if (++this._idle > this.idleMax) {
845				this._stop();
846			}
847			return;
848		}
849		var client = HTML_AJAX.httpClient();
850		if (!client) {
851			return;
852		}
853		var request = this.peek();
854		if (!request) {
855			this._requests.splice(0, 1);
856			return;
857		}
858		client.request = request.item;
859		client.makeRequest();
860		this._requests.splice(0, 1);
861		--this._len;
862		this._removed[this._removedLen++] = new HTML_AJAX_Queue_Priority_Item(request, new Date().getTime());
863	},
864	_doRetries: function () {
865		for (i = 0; i < this._removedLen; i++) {
866			if (this._removed[i].time + this._requestTimeout < new Date().getTime()) {
867				this.addRequest(request.item);
868				this._removed.splice(i, 1);
869				--this._removedLen;
870				return true;
871			}
872		}
873	},
874	_start: function() {
875		var self = this;
876		this._intervalId = setInterval(function() { self._runInterval() }, this.interval);
877	},
878	_stop: function() {
879		clearInterval(this._intervalId);
880		this._intervalId = 0;
881	}
882};
883// clientPool.js
884HTML_AJAX_Client_Pool = function(maxClients, startingClients)
885{
886	this.maxClients = maxClients;
887	this._clients = [];
888	this._len = 0;
889	while (--startingClients > 0) {
890		this.addClient();
891	}
892}
893
894HTML_AJAX_Client_Pool.prototype = {
895	isEmpty: function()
896	{
897		return this._len == 0;
898	},
899	addClient: function()
900	{
901		if (this.maxClients != 0 && this._len > this.maxClients) {
902			return false;
903		}
904		var key = this._len++;
905		this._clients[key] = new HTML_AJAX_HttpClient();
906		return this._clients[key];
907	},
908	getClient: function ()
909	{
910		for (var i = 0; i < this._len; i++) {
911			if (!this._clients[i].callInProgress() && this._clients[i].callbackComplete) {
912				return this._clients[i];
913			}
914		}
915		var client = this.addClient();
916		if (client) {
917			return client;
918		}
919		return false;
920	},
921	removeClient: function (client)
922	{
923		for (var i = 0; i < this._len; i++) {
924			if (!this._clients[i] == client) {
925				this._clients.splice(i, 1);
926				return true;
927			}
928		}
929		return false;
930	},
931	clear: function ()
932	{
933		this._clients = [];
934		this._len = 0;
935	}
936};
937
938// create a default client pool with unlimited clients
939HTML_AJAX.clientPools['default'] = new HTML_AJAX_Client_Pool(0);
940// IframeXHR.js
941/**
942 * XMLHttpRequest Iframe fallback
943 *
944 * http://lxr.mozilla.org/seamonkey/source/extensions/xmlextras/tests/ - should work with these
945 *
946 * @category	HTML
947 * @package	AJAX
948 * @author	Elizabeth Smith <[email protected]>
949 * @copyright 	2005 Elizabeth Smith
950 * @license	http://www.opensource.org/licenses/lgpl-license.php  LGPL
951 */
952HTML_AJAX_IframeXHR_instances = new Object();
953function HTML_AJAX_IframeXHR()
954{
955	this._id = 'HAXHR_iframe_' + new Date().getTime();
956	HTML_AJAX_IframeXHR_instances[this._id] = this;
957}
958HTML_AJAX_IframeXHR.prototype = {
959// Data not sent with text/xml Content-Type will only be available via the responseText property
960
961	// properties available in safari/mozilla/IE xmlhttprequest object
962	onreadystatechange: null, // Event handler for an event that fires at every state change
963	readyState: 0, // Object status integer: 0 = uninitialized 1 = loading 2 = loaded 3 = interactive 4 = complete
964	responseText: '', // String version of data returned from server process
965	responseXML: null, // DOM-compatible document object of data returned from server process
966	status: 0, // Numeric code returned by server, such as 404 for "Not Found" or 200 for "OK"
967	statusText: '', // String message accompanying the status code
968	iframe: true, // flag for iframe
969
970	//these are private properties used internally to keep track of stuff
971	_id: null, // iframe id, unique to object(hopefully)
972	_url: null, // url sent by open
973	_method: null, // get or post
974	_async: null, // sync or async sent by open
975	_headers: new Object(), //request headers to send, actually sent as form vars
976	_response: new Object(), //response headers received
977	_phpclass: null, //class to send
978	_phpmethod: null, //method to send
979	_history: null, // opera has to have history munging
980
981	// Stops the current request
982	abort: function()
983	{
984		var iframe = document.getElementById(this._id);
985		if (iframe) {
986			document.body.removeChild(iframe);
987		}
988		if (this._timeout) {
989			window.clearTimeout(this._timeout);
990		}
991		this.readyState = 1;
992		if (typeof(this.onreadystatechange) == "function") {
993			this.onreadystatechange();
994		}
995	},
996
997	// This will send all headers in this._response and will include lastModified and contentType if not already set
998	getAllResponseHeaders: function()
999	{
1000		var string = '';
1001		for (i in this._response) {
1002			string += i + ' : ' + this._response[i] + "\n";
1003		}
1004		return string;
1005	},
1006
1007	// This will use lastModified and contentType if they're not set
1008	getResponseHeader: function(header)
1009	{
1010		return (this._response[header] ? this._response[header] : null);
1011	},
1012
1013	// Assigns a label/value pair to the header to be sent with a request
1014	setRequestHeader: function(label, value) {
1015		this._headers[label] = value;
1016		return; },
1017
1018	// Assigns destination URL, method, and other optional attributes of a pending request
1019	open: function(method, url, async, username, password)
1020	{
1021		if (!document.body) {
1022			throw('CANNOT_OPEN_SEND_IN_DOCUMENT_HEAD');
1023		}
1024		//exceptions for not enough arguments
1025		if (!method || !url) {
1026			throw('NOT_ENOUGH_ARGUMENTS:METHOD_URL_REQUIRED');
1027		}
1028		//get and post are only methods accepted
1029		this._method = (method.toUpperCase() == 'POST' ? 'POST' : 'GET');
1030		this._decodeUrl(url);
1031		this._async = async;
1032		if(!this._async && document.readyState && !window.opera) {
1033			throw('IE_DOES_NOT_SUPPORT_SYNC_WITH_IFRAMEXHR');
1034		}
1035		//set status to loading and call onreadystatechange
1036		this.readyState = 1;
1037		if(typeof(this.onreadystatechange) == "function") {
1038			this.onreadystatechange();
1039		}
1040	},
1041
1042	// Transmits the request, optionally with postable string or DOM object data
1043	send: function(content)
1044	{
1045		//attempt opera history munging
1046		if (window.opera) {
1047			this._history = window.history.length;
1048		}
1049		//create a "form" for the contents of the iframe
1050		var form = '<html><body><form method="'
1051			+ (this._url.indexOf('px=') < 0 ? this._method : 'post')
1052			+ '" action="' + this._url + '">';
1053		//tell iframe unwrapper this IS an iframe
1054		form += '<input name="Iframe_XHR" value="1" />';
1055		//class and method
1056		if (this._phpclass != null) {
1057			form += '<input name="Iframe_XHR_class" value="' + this._phpclass + '" />';
1058		}
1059		if (this._phpmethod != null) {
1060			form += '<input name="Iframe_XHR_method" value="' + this._phpmethod + '" />';
1061		}
1062		// fake headers
1063		for (label in this._headers) {
1064			form += '<textarea name="Iframe_XHR_headers[]">' + label +':'+ this._headers[label] + '</textarea>';
1065		}
1066		// add id
1067		form += '<textarea name="Iframe_XHR_id">' + this._id + '</textarea>';
1068		if (content != null && content.length > 0) {
1069			form += '<textarea name="Iframe_XHR_data">' + content + '</textarea>';
1070		}
1071		form += '<input name="Iframe_XHR_HTTP_method" value="' + this._method + '" />';
1072		form += '<s'+'cript>document.forms[0].submit();</s'+'cript></form></body></html>';
1073		form = "javascript:document.write('" + form.replace(/\'/g,"\\'") + "');void(0);";
1074		this.readyState = 2;
1075		if (typeof(this.onreadystatechange) == "function") {
1076			this.onreadystatechange();
1077		}
1078		// try to create an iframe with createElement and append node
1079		try {
1080			var iframe = document.createElement('iframe');
1081			iframe.id = this._id;
1082			// display: none will fail on some browsers
1083			iframe.style.visibility = 'hidden';
1084			// for old browsers with crappy css
1085			iframe.style.border = '0';
1086			iframe.style.width = '0';
1087			iframe.style.height = '0';
1088			
1089			if (document.all) {
1090				// MSIE, opera
1091				iframe.src = form;
1092				document.body.appendChild(iframe);
1093			} else {
1094				document.body.appendChild(iframe);
1095				iframe.src = form;
1096			}
1097		} catch(exception) {
1098			// dom failed, write the sucker manually
1099			var html = '<iframe src="' + form +'" id="' + this._id + '" style="visibility:hidden;border:0;height:0;width:0;"></iframe>';
1100			document.body.innerHTML += html;
1101		}
1102		if (this._async == true) {
1103			//avoid race state if onload is called first
1104			if (this.readyState < 3) {
1105				this.readyState = 3;
1106				if(typeof(this.onreadystatechange) == "function") {
1107					this.onreadystatechange();
1108				}
1109			}
1110		} else {
1111			//we force a while loop for sync, it's ugly but hopefully it works
1112			while (this.readyState != 4) {
1113				//just check to see if we can up readyState
1114				if (this.readyState < 3) {
1115					this.readyState = 3;
1116					if(typeof(this.onreadystatechange) == "function") {
1117						this.onreadystatechange();
1118					}
1119				}
1120			}
1121		}
1122	},
1123
1124	// attached as an onload function to the iframe to trigger when we're done
1125	isLoaded: function(headers, data)
1126	{
1127		this.readyState = 4;
1128		//set responseText, Status, StatusText
1129		this.status = 200;
1130		this.statusText = 'OK';
1131		this.responseText = data;
1132		this._response = headers;
1133		if (!this._response['Last-Modified']) {
1134			string += 'Last-Modified : ' + document.getElementById(this._id).lastModified + "\n";
1135		}
1136		if (!this._response['Content-Type']) {
1137			string += 'Content-Type : ' + document.getElementById(this._id).contentType + "\n";
1138		}
1139		// if this is xml populate responseXML accordingly
1140		if (this._response['Content-Type'] == 'application/xml')
1141		{
1142			return new DOMParser().parseFromString(this.responseText, 'application/xml');
1143		}
1144		//attempt opera history munging in opera 8+ - this is a REGRESSION IN OPERA
1145		if (window.opera && window.opera.version) {
1146			//go back current history - old history
1147			window.history.go(this._history - window.history.length);
1148		}
1149		if (typeof(this.onreadystatechange) == "function") {
1150			this.onreadystatechange();
1151		}
1152		document.body.removeChild(document.getElementById(this._id));
1153	},
1154
1155	// strip off the c and m from the url send...yuck
1156	_decodeUrl: function(querystring)
1157	{
1158		//opera 7 is too stupid to do a relative url...go figure
1159		var url = unescape(location.href);
1160		url = url.substring(0, url.lastIndexOf("/") + 1);
1161		var item = querystring.split('?');
1162		//rip off any path info and append to path above <-  relative paths (../) WILL screw this
1163		this._url = url + item[0].substring(item[0].lastIndexOf("/") + 1,item[0].length);
1164		if(item[1]) {
1165			item = item[1].split('&');
1166			for (i in item) {
1167				var v = item[i].split('=');
1168				if (v[0] == 'c') {
1169					this._phpclass = v[1];
1170				} else if (v[0] == 'm') {
1171					this._phpmethod = v[1];
1172				}
1173			}
1174		}
1175		if (!this._phpclass || !this._phpmethod) {
1176			var cloc = window.location.href;
1177			this._url = cloc + (cloc.indexOf('?') >= 0 ? '&' : '?') + 'px=' + escape(HTML_AJAX_Util.absoluteURL(querystring));
1178		}
1179	}
1180}
1181// serializer/UrlSerializer.js
1182// {{{ HTML_AJAX_Serialize_Urlencoded
1183/**
1184 * URL-encoding serializer
1185 *
1186 * This class can be used to serialize and unserialize data in a
1187 * format compatible with PHP's handling of HTTP query strings.
1188 * Due to limitations of the format, all input is serialized as an
1189 * array or a string. See examples/serialize.url.examples.php
1190 *
1191 * @version	0.0.1
1192 * @copyright	2005 Arpad Ray <[email protected]>
1193 * @license	http://www.opensource.org/licenses/lgpl-license.php  LGPL
1194 *
1195 * See Main.js for Author/license details
1196 */
1197function HTML_AJAX_Serialize_Urlencoded() {}
1198HTML_AJAX_Serialize_Urlencoded.prototype = {
1199	contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
1200	base: '_HTML_AJAX',
1201	_keys: [],
1202	error: false,
1203	message: "",
1204	cont: "",
1205	// {{{ serialize
1206	/**
1207	 *  Serializes a variable
1208	 *
1209	 *  @param	mixed  inp the variable to serialize
1210	 *  @return	string   a string representation of the input, 
1211	 *					  which can be reconstructed by unserialize()
1212	 */
1213	serialize: function(input, _internal) {
1214		if (typeof input == 'undefined') {
1215			return '';
1216		}
1217		if (!_internal) {
1218			this._keys = [];
1219		}
1220		var ret = '', first = true;
1221		for (i = 0; i < this._keys.length; i++) {
1222			ret += (first ? HTML_AJAX_Util.encodeUrl(this._keys[i]) : '[' + HTML_AJAX_Util.encodeUrl(this._keys[i]) + ']');
1223			first = false;
1224		}
1225		ret += '=';
1226		switch (HTML_AJAX_Util.getType(input)) {
1227			case 'string': 
1228			case 'number':
1229				ret += HTML_AJAX_Util.encodeUrl(input.toString());
1230				break;
1231			case 'boolean':
1232				ret += (input ? '1' : '0');
1233				break;
1234			case 'array':
1235			case 'object':
1236				ret = '';
1237				for (i in input) {
1238					this._keys.push(i);
1239					ret += this.serialize(input[i], true) + '&';
1240					this._keys.pop();
1241				}
1242				ret = ret.substr(0, ret.length - 1);
1243		}
1244		return ret;
1245	},
1246	// }}}
1247	// {{{ unserialize
1248	/**
1249	 *  Reconstructs a serialized variable
1250	 *
1251	 *  @param	string inp the string to reconstruct
1252	 *  @return	array an array containing the variable represented by the input string, or void on failure
1253	 */
1254	unserialize: function(input) {
1255		if (!input.length || input.length == 0) {
1256			// null
1257			return;
1258		}
1259		if (!/^(\w+(\[[^\[\]]*\])*=[^&]*(&|$))+$/.test(input)) {
1260			this.raiseError("invalidly formed input", input);
1261			return;
1262		}
1263		input = input.split("&");
1264		var pos, key, keys, val, _HTML_AJAX = [];
1265		if (input.length == 1) {
1266			return HTML_AJAX_Util.decodeUrl(input[0].substr(this.base.length + 1));
1267		}
1268		for (var i in input) {
1269			pos = input[i].indexOf("=");
1270			if (pos < 1 || input[i].length - pos - 1 < 1) {
1271				this.raiseError("input is too short", input[i]);
1272				return;
1273			}
1274			key = HTML_AJAX_Util.decodeUrl(input[i].substr(0, pos));
1275			val = HTML_AJAX_Util.decodeUrl(input[i].substr(pos + 1));
1276			key = key.replace(/\[((\d*\D+)+)\]/g, '["$1"]');
1277			keys = key.split(']');
1278			for (j in keys) {
1279				if (!keys[j].length || keys[j].length == 0) {
1280					continue;
1281				}
1282				try {
1283					if (eval('typeof ' + keys[j] + ']') == 'undefined') {
1284						var ev = keys[j] + ']=[];';
1285						eval(ev);
1286					}
1287				} catch (e) {
1288					this.raiseError("error evaluating key", ev);
1289					return; 
1290				}
1291			}
1292			try {
1293				eval(key + '="' + val + '";');
1294			} catch (e) {
1295				this.raiseError("error evaluating value", input);
1296				return; 
1297			}
1298		}
1299		return _HTML_AJAX;
1300	},
1301	// }}}
1302	// {{{ getError
1303	/**
1304	*  Gets the last error message
1305	*
1306	*  @return	string   the last error message from unserialize()
1307	*/	
1308	getError: function() {
1309		return this.message + "\n" + this.cont;
1310	},
1311	// }}}
1312	// {{{ raiseError
1313	/**
1314	*  Raises an eror (called by unserialize().)
1315	*
1316	*  @param	string	message	the error message
1317	*  @param	string	cont	   the remaining unserialized content
1318	*/	
1319	raiseError: function(message, cont) {
1320		this.error = 1;
1321		this.message = message;
1322		this.cont = cont;
1323	}
1324	// }}}
1325}
1326// }}}
1327// serializer/phpSerializer.js
1328// {{{ HTML_AJAX_Serialize_PHP
1329/**
1330 * PHP serializer
1331 *
1332 * This class can be used to serialize and unserialize data in a
1333 * format compatible with PHP's native serialization functions.
1334 *
1335 * @version	0.0.3
1336 * @copyright	2005 Arpad Ray <[email protected]>
1337 * @license	http://www.opensource.org/licenses/lgpl-license.php  LGPL
1338 *
1339 * See Main.js for Author/license details
1340 */
1341
1342function HTML_AJAX_Serialize_PHP() {}
1343HTML_AJAX_Serialize_PHP.prototype = {
1344	error: false,
1345	message: "",
1346	cont: "",
1347	defaultEncoding: 'UTF-8',
1348	contentType: 'application/php-serialized; charset: UTF-8',
1349	// {{{ serialize
1350	/**
1351	*  Serializes a variable
1352	*
1353	*  @param	mixed  inp the variable to serialize
1354	*  @return	string   a string representation of the input, 
1355	*					  which can be reconstructed by unserialize()
1356	*  @author Arpad Ray <[email protected]>
1357	*  @author David Coallier <[email protected]>
1358	*/
1359	serialize: function(inp) {
1360		var type = HTML_AJAX_Util.getType(inp);
1361		var val;
1362		switch (type) {
1363			case "undefined":
1364				val = "N";
1365				break;
1366			case "boolean":
1367				val = "b:" + (inp ? "1" : "0");
1368				break;
1369			case "number":
1370				val = (Math.round(inp) == inp ? "i" : "d") + ":" + inp;
1371				break;
1372			case "string":
1373				val = "s:" + inp.length + ":\"" + inp + "\"";
1374				break;
1375			case "array":
1376				val = "a";
1377			case "object":
1378				if (type == "object") {
1379					var objname = inp.constructor.toString().match(/(\w+)\(\)/);
1380					if (objname == undefined) {
1381						return;
1382					}
1383					objname[1] = this.serialize(objname[1]);
1384					val = "O" + objname[1].substring(1, objname[1].length - 1);
1385				}
1386				var count = 0;
1387				var vals = "";
1388				var okey;
1389				for (key in inp) {
1390					okey = (key.match(/^[0-9]+$/) ? parseInt(key) : key);
1391					vals += this.serialize(okey) + 
1392							this.serialize(inp[key]);
1393					count++;
1394				}
1395				val += ":" + count + ":{" + vals + "}";
1396				break;
1397		}
1398		if (type != "object" && type != "array") val += ";";
1399		return val;
1400	},
1401	// }}} 
1402	// {{{ unserialize
1403	/**
1404	 *  Reconstructs a serialized variable
1405	 *
1406	 *  @param	string inp the string to reconstruct
1407	 *  @return   mixed the variable represented by the input string, or void on failure
1408	 */
1409	unserialize: function(inp) {
1410		this.error = 0;
1411		if (inp == "" || inp.length < 2) {
1412			this.raiseError("input is too short");
1413			return;
1414		}
1415		var val, kret, vret, cval;
1416		var type = inp.charAt(0);
1417		var cont = inp.substring(2);
1418		var size = 0, divpos = 0, endcont = 0, rest = "", next = "";
1419
1420		switch (type) {
1421		case "N": // null
1422			if (inp.charAt(1) != ";") {
1423				this.raiseError("missing ; for null", cont);
1424			}
1425			// leave val undefined
1426			rest = cont;
1427			break;
1428		case "b": // boolean
1429			if (!/[01];/.test(cont.substring(0,2))) {
1430				this.raiseError("value not 0 or 1, or missing ; for boolean", cont);
1431			}
1432			val = (cont.charAt(0) == "1");
1433			rest = cont.substring(1);
1434			break;
1435		case "s": // string
1436			val = "";
1437			divpos = cont.indexOf(":");
1438			if (divpos == -1) {
1439				this.raiseError("missing : for string", cont);
1440				break;
1441			}
1442			size = parseInt(cont.substring(0, divpos));
1443			if (size == 0) {
1444				if (cont.length - divpos < 4) {
1445					this.raiseError("string is too short", cont);
1446					break;
1447				}
1448				rest = cont.substring(divpos + 4);
1449				break;
1450			}
1451			if ((cont.length - divpos - size) < 4) {
1452				this.raiseError("string is too short", cont);
1453				break;
1454			}
1455			if (cont.substring(divpos + 2 + size, divpos + 4 + size) != "\";") {
1456				this.raiseError("string is too long, or missing \";", cont);
1457			}
1458			val = cont.substring(divpos + 2, divpos + 2 + size);
1459			rest = cont.substring(divpos + 4 + size);
1460			break;
1461		case "i": // integer
1462		case "d": // float
1463			var dotfound = 0;
1464			for (var i = 0; i < cont.length; i++) {
1465				cval = cont.charAt(i);
1466				if (isNaN(parseInt(cval)) && !(type == "d" && cval == "." && !dotfound++)) {
1467					endcont = i;
1468					break;
1469				}
1470			}
1471			if (!endcont || cont.charAt(endcont) != ";") {
1472				this.raiseError("missing or invalid value, or missing ; for int/float", cont);
1473			}
1474			val = cont.substring(0, endcont);
1475			val = (type == "i" ? parseInt(val) : parseFloat(val));
1476			rest = cont.substring(endcont + 1);
1477			break;
1478		case "a": // array
1479			if (cont.length < 4) {
1480				this.raiseError("array is too short", cont);
1481				return;
1482			}
1483			divpos = cont.indexOf(":", 1);
1484			if (divpos == -1) {
1485				this.raiseError("missing : for array", cont);
1486				return;
1487			}
1488			size = parseInt(cont.substring(0, divpos));
1489			cont = cont.substring(divpos + 2);
1490			val = new Array();
1491			if (cont.length < 1) {
1492				this.raiseError("array is too short", cont);
1493				return;
1494			}
1495			for (var i = 0; i < size; i++) {
1496				kret = this.unserialize(cont, 1);
1497				if (this.error || kret[0] == undefined || kret[1] == "") {
1498					this.raiseError("missing or invalid key, or missing value for array", cont);
1499					return;
1500				}
1501				vret = this.unserialize(kret[1], 1);
1502				if (this.error) {
1503					this.raiseError("invalid value for array", cont);
1504					return;
1505				}
1506				val[kret[0]] = vret[0];
1507				cont = vret[1];
1508			}
1509			if (cont.charAt(0) != "}") {
1510				this.raiseError("missing ending }, or too many values for array", cont);
1511				return; 
1512			}
1513			rest = cont.substring(1);
1514			break;
1515		case "O": // object
1516			divpos = cont.indexOf(":");
1517			if (divpos == -1) {
1518				this.raiseError("missing : for object", cont);
1519				return;
1520			}
1521			size = parseInt(cont.substring(0, divpos));
1522			var objname = cont.substring(divpos + 2, divpos + 2 + size);
1523			if (cont.substring(divpos + 2 + size, divpos + 4 + size) != "\":") {
1524				this.raiseError("object name is too long, or missing \":", cont);
1525				return;
1526			}
1527			var objprops = this.unserialize("a:" + cont.substring(divpos + 4 + size), 1);
1528			if (this.error) {
1529				this.raiseError("invalid object properties", cont);
1530				return;
1531			}
1532			rest = objprops[1];
1533			var objout = "function " + objname + "(){";
1534			for (key in objprops[0]) {
1535				objout += "this." + key + "=objprops[0]['" + key + "'];";
1536			}
1537			objout += "}val=new " + objname + "();";
1538			eval(objout);
1539			break;
1540		default:
1541			this.raiseError("invalid input type", cont);
1542		}
1543		return (arguments.length == 1 ? val : [val, rest]);
1544	},
1545	// }}}
1546	// {{{ getError
1547	/**
1548	*  Gets the last error message
1549	*
1550	*  @return	string   the last error message from unserialize()
1551	*/	
1552	getError: function() {
1553		return this.message + "\n" + this.cont;
1554	},
1555	// }}}
1556	// {{{ raiseError
1557	/**
1558	*  Raises an eror (called by unserialize().)
1559	*
1560	*  @param	string	message	the error message
1561	*  @param	string	cont	   the remaining unserialized content
1562	*/	
1563	raiseError: function(message, cont) {
1564		this.error = 1;
1565		this.message = message;
1566		this.cont = cont;
1567	}
1568	// }}}
1569}
1570// }}}
1571
1572// Dispatcher.js
1573/**
1574 * Class that is used by generated stubs to make actual AJAX calls
1575 *
1576 * @category    HTML
1577 * @package 	AJAX
1578 * @author	Joshua Eichorn <[email protected]>
1579 * @copyright   2005 Joshua Eichorn
1580 * @license 	http://www.opensource.org/licenses/lgpl-license.php  LGPL
1581 */
1582function HTML_AJAX_Dispatcher(className,mode,callback,serverUrl,serializerType) 
1583{
1584	this.className = className;
1585	this.mode = mode;
1586	this.callback = callback;
1587	this.serializerType = serializerType;
1588
1589	if (serverUrl) {
1590		this.serverUrl = serverUrl
1591	}
1592	else {
1593		this.serverUrl = window.location;
1594	}
1595}
1596
1597HTML_AJAX_Dispatcher.prototype = {
1598	/**
1599	 * Queue to use when making a request
1600	 */
1601	queue: 'default',
1602
1603	/**
1604	 * Timeout for async calls
1605	 */
1606	timeout: 20000,
1607 
1608	/**
1609	 * Default request priority
1610	 */
1611	priority: 0,
1612
1613	/**
1614	 * Request options 
1615	 */
1616	options: {},
1617	
1618	/**
1619	 * Make an ajax call
1620	 *
1621	 * @param   string callName
1622	 * @param   Array   args	arguments to the report method
1623	 */
1624	doCall: function(callName,args) 
1625	{
1626		var request = new HTML_AJAX_Request();
1627		request.requestUrl = this.serverUrl;
1628		request.className = this.className;
1629		request.methodName = callName;
1630		request.timeout = this.timeout;
1631		request.contentType = this.contentType;
1632		request.serializer = eval('new HTML_AJAX_Serialize_'+this.serializerType);
1633		request.queue = this.queue;
1634		request.priority = this.priority;
1635
1636		for(var i in this.options) {
1637			request[i] = this.options[i];
1638		}
1639		
1640		for(var i=0; i < args.length; i++) {
1641			request.addArg(i,args[i]);
1642		};
1643
1644		if ( this.mode == "async" ) {
1645			request.isAsync = true;
1646			if (this.callback[callName]) {
1647				var self = this;
1648				request.callback = function(result) { self.callback[callName](result); }
1649			}
1650
1651		} else {
1652			request.isAsync = false;
1653		}
1654
1655		return HTML_AJAX.makeRequest(request);
1656	},
1657
1658	Sync: function() 
1659	{
1660		this.mode = 'sync';
1661	},
1662
1663	Async: function(callback)
1664	{
1665		this.mode = 'async';
1666		if (callback) {
1667			this.callback = callback;
1668		}
1669	}
1670};
1671// HttpClient.js
1672/**
1673 * XMLHttpRequest Wrapper
1674 * @category    HTML
1675 * @package 	AJAX
1676 * @author      Joshua Eichorn <[email protected]>
1677 * @copyright   2005 Joshua Eichorn
1678 * @license     http://www.opensource.org/licenses/lgpl-license.php  LGPL
1679 */
1680function HTML_AJAX_HttpClient() { }
1681HTML_AJAX_HttpClient.prototype = {
1682	// request object
1683	request: null,
1684
1685	// timeout id
1686	_timeoutId: null,
1687
1688	callbackComplete: true,
1689
1690	// has this request been aborted
1691	aborted: false,
1692	
1693	// method to initialize an xmlhttpclient
1694	init:function() 
1695	{
1696		try {
1697			// Mozilla / Safari
1698			//this.xmlhttp = new HTML_AJAX_IframeXHR(); //uncomment these two lines to test iframe
1699			//return;
1700			this.xmlhttp = new XMLHttpRequest();
1701		} catch (e) {
1702			// IE
1703			var XMLHTTP_IDS = new Array(
1704			'MSXML2.XMLHTTP.5.0',
1705			'MSXML2.XMLHTTP.4.0',
1706			'MSXML2.XMLHTTP.3.0',
1707			'MSXML2.XMLHTTP',
1708			'Microsoft.XMLHTTP' );
1709			var success = false;
1710			for (var i=0;i < XMLHTTP_IDS.length && !success; i++) {
1711				try {
1712					this.xmlhttp = new ActiveXObject(XMLHTTP_IDS[i]);
1713					success = true;
1714				} catch (e) {}
1715			}
1716			if (!success) {
1717				try{
1718					this.xmlhttp = new HTML_AJAX_IframeXHR();
1719					this.request.iframe = true;
1720				} catch(e) {
1721					throw new Error('Unable to create XMLHttpRequest.');
1722				}
1723			}
1724		}
1725	},
1726
1727	// check if there is a call in progress
1728	callInProgress: function() 
1729	{
1730		switch ( this.xmlhttp.readyState ) {
1731			case 1:
1732			case 2:
1733			case 3:
1734				return true;
1735			break;
1736			default:
1737				return false;
1738			break;
1739		}
1740	},
1741
1742	// make the request defined in the request object
1743	makeRequest: function() 
1744	{
1745		if (!this.xmlhttp) {
1746			this.init();
1747		}
1748
1749		try {
1750			if (this.request.Open) {
1751				this.request.Open();
1752			}
1753			else if (HTML_AJAX.Open) {
1754				HTML_AJAX.Open(this.request);
1755			}
1756
1757			if (this.request.multipart) {
1758				if (document.all) {
1759					this.iframe = true;
1760				} else {
1761					this.xmlhttp.multipart = true;
1762				}
1763			}
1764	
1765			// set onreadystatechange here since it will be reset after a completed call in Mozilla
1766			var self = this;
1767			this.xmlhttp.open(this.request.requestType,this.request.completeUrl(),this.request.isAsync);
1768			if (this.request.customHeaders) {
1769				for (var i in this.request.customHeaders) {
1770					this.xmlhttp.setRequestHeader(i, this.request.customHeaders[i]);
1771				}
1772			}
1773			if (this.request.customHeaders && !this.request.customHeaders['Content-Type']) {
1774				var content = this.request.getContentType();
1775				var charsetIndex = content.indexOf('; charset=UTF-8');
1776				if (charsetIndex == -1) {
1777					content += '; charset=UTF-8';
1778				}
1779				this.xmlhttp.setRequestHeader('Content-Type', content);
1780			}
1781
1782			if (this.request.isAsync) {
1783				if (this.request.callback) {
1784					this.callbackComplete = false;
1785				}
1786				this.xmlhttp.onreadystatechange = function() { self._readyStateChangeCallback(); }
1787			} else {
1788				this.xmlhttp.onreadystatechange = function() {}
1789			}
1790			var payload = this.request.getSerializedPayload();
1791			if (payload) {
1792				this.xmlhttp.setRequestHeader('Content-Length', payload.length);
1793			}
1794			this.xmlhttp.send(payload);
1795
1796			if (!this.request.isAsync) {
1797				if ( this.xmlhttp.status == 200 ) {
1798					HTML_AJAX.requestComplete(this.request);
1799					if (this.request.Load) {
1800						this.request.Load();
1801					} else if (HTML_AJAX.Load) {
1802						HTML_AJAX.Load(this.request);
1803					}
1804						
1805					return this._decodeResponse();
1806				} else {
1807					var e = new Error('['+this.xmlhttp.status +'] '+this.xmlhttp.statusText);
1808					e.headers = this.xmlhttp.getAllResponseHeaders();
1809					this._handleError(e);
1810				}
1811			}
1812			else {
1813				// setup timeout
1814				var self = this;
1815				this._timeoutId = window.setTimeout(function() { self.abort(true); },this.request.timeout);
1816			}
1817		} catch (e) {
1818			this._handleError(e);
1819		}
1820	},
1821	
1822	// abort an inprogress request
1823	abort: function (automatic) 
1824	{
1825		if (this.callInProgress()) {
1826			this.aborted = true;
1827			this.xmlhttp.abort();
1828
1829			if (automatic) {
1830				HTML_AJAX.requestComplete(this.request);
1831				this._handleError(new Error('Request Timed Out: time out was '+this.request.timeout+'ms'));
1832			}
1833		}
1834	},
1835
1836	// internal method used to handle ready state changes
1837	_readyStateChangeCallback:function() 
1838	{
1839		try {
1840			switch(this.xmlhttp.readyState) {
1841				// XMLHTTPRequest.open() has just been called
1842				case 1:
1843					break;
1844				// XMLHTTPRequest.send() has just been called
1845				case 2:
1846					if (this.request.Send) {
1847						this.request.Send();
1848					} else if (HTML_AJAX.Send) {
1849						HTML_AJAX.Send(this.request);
1850					}
1851					break;
1852				// Fetching response from server in progress
1853				case 3:
1854					if (this.request.Progress) {
1855						this.request.Progress();
1856					} else if (HTML_AJAX.Progress ) {
1857						HTML_AJAX.Progress(this.request);
1858					}
1859				break;
1860				// Download complete
1861				case 4:
1862					window.clearTimeout(this._timeoutId);
1863					if (this.aborted) {
1864						if (this.request.Load) {
1865							this.request.Load();
1866						} else if (HTML_AJAX.Load) {
1867							HTML_AJAX.Load(this.request);
1868						}
1869					}
1870					else if (this.xmlhttp.status == 200) {
1871						if (this.request.Load) {
1872							this.request.Load();
1873						} else if (HTML_AJAX.Load ) {
1874							HTML_AJAX.Load(this.request);
1875						}
1876
1877						var response = this._decodeResponse();
1878
1879						if (this.request.callback) {
1880							this.request.callback(response);
1881							this.callbackComplete = true;
1882						}
1883					}
1884					else {
1885						var e = new Error('HTTP Error Making Request: ['+this.xmlhttp.status+'] '+this.xmlhttp.statusText);
1886						this._handleError(e);
1887					}
1888					HTML_AJAX.requestComplete(this.request);
1889				break;
1890			}
1891		} catch (e) {
1892				this._handleError(e);
1893		}
1894	},
1895
1896	// decode response as needed
1897	_decodeResponse: function() {
1898		//try for x-Content-Type first
1899		var content = null;
1900		try {
1901			content = this.xmlhttp.getResponseHeader('X-Content-Type');
1902		} catch(e) {}
1903		if(!content || content == null)
1904		{
1905			content = this.xmlhttp.getResponseHeader('Content-Type');
1906		}
1907		//strip anything after ;
1908		if(content.indexOf(';') != -1)
1909		{
1910			content = content.substring(0, content.indexOf(';'));
1911		}
1912		// hook for xml, it doesn't need to be unserialized
1913		if(content == 'application/xml' || content == 'text/xml')
1914		{
1915			return this.xmlhttp.responseXML;
1916		}
1917		var unserializer = HTML_AJAX.serializerForEncoding(content);
1918		//alert(this.xmlhttp.getAllResponseHeaders()); // some sort of debug hook is needed here
1919		return unserializer.unserialize(this.xmlhttp.responseText);
1920	},
1921
1922	// handle sending an error where it needs to go
1923	_handleError: function(e) 
1924	{
1925		HTML_AJAX.requestComplete(this.request,e);
1926		if (this.request.onError) {
1927			this.request.onError(e);
1928		} else if (HTML_AJAX.onError) {
1929			HTML_AJAX.onError(e,this.request);
1930		}
1931		else {
1932			throw e;
1933		}
1934	}
1935}
1936// Request.js
1937/**
1938 * Class that contains everything needed to make a request
1939 * This includes:
1940 *	The url were calling
1941 *	If were calling a remote method, the class and method name
1942 *	The payload, unserialized
1943 *	The timeout for async calls
1944 *	The callback method
1945 *	Optional event handlers: onError, Load, Send
1946 *	A serializer instance
1947 *
1948 * @category	HTML
1949 * @package	AJAX
1950 * @author	Joshua Eichorn <[email protected]>
1951 * @copyright	2005 Joshua Eichorn
1952 * @license	http://www.opensource.org/licenses/lgpl-license.php  LGPL
1953 *
1954 * See Main.js for author/license details
1955 */
1956function HTML_AJAX_Request(serializer) {
1957	this.serializer = serializer;
1958}
1959HTML_AJAX_Request.prototype = {
1960
1961	// Instance of a serializer
1962	serializer: null,
1963
1964	// Is this an async request
1965	isAsync: false,
1966
1967	// HTTP verb
1968	requestType: 'POST',
1969
1970	// The actual URL the request is sent to
1971	requestUrl: '',
1972
1973	// Remote Class
1974	className: null,
1975
1976	// Remote Method
1977	methodName: null,
1978
1979	// Timeout in milliseconds for requests
1980	timeout: 20000,
1981
1982	// unserialized data, for rpc calls use add args, to send raw data just set this directly
1983	args: null,
1984
1985	// async callback method
1986	callback: null,
1987
1988	// Queue to push this request too
1989	queue: 'default',
1990
1991	// default priority
1992	priority: 0,
1993
1994	// a hash of headers to add to add to this request
1995	customHeaders: {'X-Requested-With': 'XMLHttpRequest', 'X-Ajax-Engine': 'HTML_AJAX/0.5.6'},
1996
1997	// true if this request will be sent using iframes
1998	iframe: false,
1999
2000	// is this a grab request? if so we need to proxy for iframes
2001	grab: false,
2002
2003	// true if this request should expect a multipart response
2004	multipart: false,
2005
2006	// remote callback
2007	phpCallback: false,
2008
2009	/**
2010	 * Add an argument for the remote method
2011	 * @param string argument name
2012	 * @param mixed value
2013	 * @return void
2014	 * @throws Error code 1004
2015	 */
2016	addArg: function(name, value) 
2017	{
2018		if ( !this.args ) {
2019			this.args = [];
2020		}
2021		if (!/[^a-zA-Z_0-9]/.test(name) ) {
2022			this.args[name] = value;
2023		} else {
2024			throw new Error('Invalid parameter name ('+name+')');
2025		}
2026	},
2027
2028	/**
2029	 * Get the payload in a serialized manner
2030	 */
2031	getSerializedPayload: function() {
2032		return this.serializer.serialize(this.args);
2033	},
2034
2035	/**
2036	 * Get the content type
2037	 */
2038	getContentType: function() {
2039		return this.serializer.contentType;
2040	},
2041
2042	/**
2043	 * Get the complete url, adding in any needed get params for rpc
2044	 */
2045	completeUrl: function() {
2046		if (this.className || this.methodName) {
2047			this.addGet('c', this.className);
2048			this.addGet('m', this.methodName);
2049		}
2050		if (this.phpCallback) {
2051			if (HTML_AJAX_Util.getType(this.phpCallback) == 'array') {
2052				this.phpCallback = this.phpCallback.join('.');
2053			}
2054			this.addGet('cb', this.phpCallback);
2055		}
2056		if (this.multipart) {
2057			this.addGet('multipart', '1');
2058		}
2059		return this.requestUrl;
2060	},
2061
2062	/**
2063	 * Compare to another request by priority
2064	 */
2065	compareTo: function(other) {
2066		if (this.priority == other.priority) {
2067			return 0;
2068		}
2069		return (this.priority > other.priority ? 1 : -1);
2070	},
2071
2072	/**
2073	 * Add a GET argument
2074	 */
2075	addGet: function(name, value) {
2076		var url = new String(this.requestUrl);
2077		url += (url.indexOf('?') < 0 ? '?' : '&') + escape(name) + '=' + escape(value);
2078		this.requestUrl = url;
2079	}
2080}
2081// serializer/JSON.js
2082/*
2083Copyright (c) 2005 JSON.org
2084
2085Permission is hereby granted, free of charge, to any person obtaining a copy
2086of this software and associated documentation files (the "Software"), to deal
2087in the Software without restriction, including without limitation the rights
2088to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2089copies of the Software, and to permit persons to whom the Software is
2090furnished to do so, subject to the following conditions:
2091
2092The Software shall be used for Good, not Evil.
2093
2094THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2095IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2096FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2097AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2098LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2099OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2100SOFTWARE.
2101*/
2102
2103/*
2104    The global object JSON contains two methods.
2105
2106    JSON.stringify(value) takes a JavaScript value and produces a JSON text.
2107    The value must not be cyclical.
2108
2109    JSON.parse(text) takes a JSON text and produces a JavaScript value. It will
2110    throw a 'JSONError' exception if there is an error.
2111*/
2112var HTML_AJAX_JSON = {
2113    copyright: '(c)2005 JSON.org',
2114    license: 'http://www.crockford.com/JSON/license.html',
2115/*
2116    Stringify a JavaScript value, producing a JSON text.
2117*/
2118    stringify: function (v) {
2119        var a = [];
2120
2121/*
2122    Emit a string.
2123*/
2124        function e(s) {
2125            a[a.length] = s;
2126        }
2127
2128/*
2129    Convert a value.
2130*/
2131        function g(x) {
2132            var c, i, l, v;
2133
2134            switch (typeof x) {
2135            case 'object':
2136                if (x) {
2137                    if (x instanceof Array) {
2138                        e('[');
2139                        l = a.length;
2140                        for (i = 0; i < x.length; i += 1) {
2141                            v = x[i];
2142                            if (typeof v != 'undefined' &&
2143                                    typeof v != 'function') {
2144                                if (l < a.length) {
2145                                    e(',');
2146                                }
2147                                g(v);
2148                            }
2149                        }
2150                        e(']');
2151                        return;
2152                    } else if (typeof x.valueOf == 'function') {
2153                        e('{');
2154                        l = a.length;
2155                        for (i in x) {
2156                            v = x[i];
2157                            if (typeof v != 'undefined' &&
2158                                    typeof v != 'function' &&
2159                                    (!v || typeof v != 'object' ||
2160                                        typeof v.valueOf == 'function')) {
2161                                if (l < a.length) {
2162                                    e(',');
2163                                }
2164                                g(i);
2165                                e(':');
2166                                g(v);
2167                            }
2168                        }
2169                        return e('}');
2170                    }
2171                }
2172                e('null');
2173                return;
2174            case 'number':
2175                e(isFinite(x) ? +x : 'null');
2176                return;
2177            case 'string':
2178                l = x.length;
2179                e('"');
2180                for (i = 0; i < l; i += 1) {
2181                    c = x.charAt(i);
2182                    if (c >= ' ') {
2183                        if (c == '\\' || c == '"') {
2184                            e('\\');
2185                        }
2186                        e(c);
2187                    } else {
2188                        switch (c) {
2189                        case '\b':
2190                            e('\\b');
2191                            break;
2192                        case '\f':
2193                            e('\\f');
2194                            break;
2195                        case '\n':
2196                            e('\\n');
2197                            break;
2198                        case '\r':
2199                            e('\\r');
2200                            break;
2201                        case '\t':
2202                            e('\\t');
2203                            break;
2204                        default:
2205                            c = c.charCodeAt();
2206                            e('\\u00' + Math.floor(c / 16).toString(16) +
2207                                (c % 16).toString(16));
2208                        }
2209                    }
2210                }
2211                e('"');
2212                return;
2213            case 'boolean':
2214                e(String(x));
2215                return;
2216            default:
2217                e('null');
2218                return;
2219            }
2220        }
2221        g(v);
2222        return a.join('');
2223    },
2224/*
2225    Parse a JSON text, producing a JavaScript value.
2226*/
2227    parse: function (text) {
2228        return 
2229(/^(\s+|[,:{}\[\]]|"(\\["\\\/bfnrtu]|[^\x00-\x1f"\\]+)*"|-?\d+(\.\d*)?([eE][+-]?\d+)?|true|false|null)+$/.test(text))
2230 &&
2231            eval('(' + text + ')');
2232    }
2233};// serializer/haSerializer.js
2234/**
2235 * HTML_AJAX_Serialize_HA  - custom serialization
2236 *
2237 * This class is used with the JSON serializer and the HTML_AJAX_Action php class
2238 * to allow users to easily write data handling and dom manipulation related to
2239 * ajax actions directly from their php code
2240 *
2241 * See Main.js for Author/license details
2242 */
2243function HTML_AJAX_Serialize_HA() { }
2244HTML_AJAX_Serialize_HA.prototype =
2245{
2246	/**
2247	 *  Takes data from JSON - which should be parseable into a nice array
2248	 *  reads the action to take and pipes it to the right method
2249	 *
2250	 *  @param   string payload incoming data from php
2251	 *  @return   true on success, false on failure
2252	 */
2253	unserialize: function(payload)
2254	{
2255		var actions = eval(payload);
2256		for(var i = 0; i < actions.length; i++)
2257		{
2258			var action = actions[i];
2259			switch(action.action)
2260			{
2261				case 'prepend':
2262					this._prependAttr(action.id, action.attributes);
2263					break;
2264				case 'append':
2265					this._appendAttr(action.id, action.attributes);
2266					break;
2267				case 'assign':
2268					this._assignAttr(action.id, action.attributes);
2269					break;
2270				case 'clear':
2271					this._clearAttr(action.id, action.attributes);
2272					break;
2273				case 'create':
2274					this._createNode(action.id, action.tag, action.attributes, action.type);
2275					break;
2276				case 'replace':
2277					this._replaceNode(action.id, action.tag, action.attributes);
2278					break;
2279				case 'remove':
2280					this._removeNode(action.id);
2281					break;
2282				case 'script':
2283					this._insertScript(action.data);
2284					break;
2285				case 'alert':
2286					this._insertAlert(action.data);
2287					break;
2288			}
2289		}
2290	},
2291	/* Dispatch Methods */
2292	_prependAttr: function(id, attributes)
2293	{
2294		var node = document.getElementById(id);
2295		this._setAttrs(node, attributes, 'prepend');
2296	},
2297	_appendAttr: function(id, attributes)
2298	{
2299		var node = document.getElementById(id);
2300		this._setAttrs(node, attributes, 'append');
2301	},
2302	_assignAttr: function(id, attributes)
2303	{
2304		var node = document.getElementById(id);
2305		this._setAttrs(node, attributes);
2306	},
2307	_clearAttr: function(id, attributes)
2308	{
2309		var node = document.getElementById(id);
2310		for(var i = 0; i < attributes.length; i++)
2311		{
2312			if(attributes[i] == 'innerHTML')
2313			{
2314				HTML_AJAX_Util.setInnerHTML(node, '');
2315			}
2316			// value can't be removed
2317			else if(attributes[i] == 'value')
2318			{
2319				node.value = '';
2320			}
2321			// I'd use hasAttribute first but IE is stupid stupid stupid
2322			else
2323			{
2324				try
2325				{
2326					node.removeAttribute(attributes[i]);
2327				}
2328				catch(e)
2329				{
2330					node[i] = undefined;
2331				}
2332			}
2333		}
2334	},
2335	_createNode: function(id, tag, attributes, type)
2336	{
2337		var newnode = document.createElement(tag);
2338		this._setAttrs(newnode, attributes);
2339		switch(type)
2340		{
2341			case 'append':
2342				document.getElementById(id).appendChild(newnode);
2343				break
2344			case 'prepend':
2345				var parent = document.getElementById(id);
2346				var sibling = parent.firstChild;
2347				parent.insertBefore(newnode, sibling);
2348				break;
2349			case 'insertBefore':
2350				var sibling = document.getElementById(id);
2351				var parent = sibling.parentNode;
2352				parent.insertBefore(newnode, sibling);
2353				break;
2354			//this one is tricky, if it's the last one we use append child...ewww
2355			case 'insertAfter':
2356				var sibling = document.getElementById(id);
2357				var parent = sibling.parentNode;
2358				var next = sibling.nextSibling;
2359				if(next == null)
2360				{
2361					parent.appendChild(newnode);
2362				}
2363				else
2364				{
2365					parent.insertBefore(newnode, next);
2366				}
2367				break;
2368		}
2369	},
2370	_replaceNode: function(id, tag, attributes)
2371	{
2372		var node = document.getElementById(id);
2373		var parent = node.parentNode;
2374		var newnode = document.createElement(tag);
2375		this._setAttrs(newnode, attributes);
2376		parent.replaceChild(newnode, node);
2377	},
2378	_removeNode: function(id)
2379	{
2380		var node = document.getElementById(id);
2381		if(node)
2382		{
2383			var parent = node.parentNode;
2384			parent.removeChild(node);
2385		}
2386	},
2387	_insertScript: function(data)
2388	{
2389		eval(data);
2390	},
2391	_insertAlert: function(data)
2392	{
2393		alert(data);
2394	},
2395	/* Helper Methods */
2396	// should we move this to HTML_AJAX_Util???, just does the - case which we need for style
2397	_camelize: function(instr)
2398	{
2399		var p = instr.split('-');
2400		var out = p[0];
2401		for(var i = 1; i < p.length; i++) {
2402			out += p[i].charAt(0).toUpperCase()+p[i].substring(1);
2403		}
2404		return out;
2405	},
2406	_setAttrs: function(node, attributes, type)
2407	{
2408		switch(type)
2409		{
2410			case 'prepend':
2411				for (var i in attributes)
2412				{
2413					// innerHTML is extremely flakey - use util method for it
2414					if(i == 'innerHTML')
2415					{
2416						HTML_AJAX_Util.setInnerHTML(node, attributes[i], 'append');
2417					}
2418					//IE doesn't support setAttribute on style so we need to break it out and set each property individually
2419					else if(i == 'style')
2420					{
2421						var styles = [];
2422						if(attributes[i].indexOf(';'))
2423						{
2424							styles = attributes[i].split(';');
2425						}
2426						else
2427						{
2428							styles.push(attributes[i]);
2429						}
2430						for(var i = 0; i < styles.length; i++)
2431						{
2432							var r = styles[i].match(/^\s*(.+)\s*:\s*(.+)\s*$/);
2433							if(r)
2434							{
2435								node.style[this._camelize(r[1])] = r[2] + node.style[this._camelize(r[1])];
2436							}
2437						}
2438					}
2439					else
2440					{
2441						try
2442						{
2443							node[i] = attributes[i] + node[i];
2444						}
2445						catch(e){}
2446						node.setAttribute(i, attributes[i] + node[i]);
2447					}
2448				}
2449				break;
2450			case 'append':
2451			{
2452				for (var i in attributes)
2453				{
2454					// innerHTML is extremely flakey - use util method for it
2455					if(i == 'innerHTML')
2456					{
2457						HTML_AJAX_Util.setInnerHTML(node, attributes[i], 'append');
2458					}
2459					//IE doesn't support setAttribute on style so we need to break it out and set each property individually
2460					else if(i == 'style')
2461					{
2462						var styles = [];
2463						if(attributes[i].indexOf(';'))
2464						{
2465							styles = attributes[i].split(';');
2466						}
2467						else
2468						{
2469							styles.push(attributes[i]);
2470						}
2471						for(var i = 0; i < styles.length; i++)
2472						{
2473							var r = styles[i].match(/^\s*(.+)\s*:\s*(.+)\s*$/);
2474							if(r)
2475							{
2476								node.style[this._camelize(r[1])] = node.style[this._camelize(r[1])] + r[2];
2477							}
2478						}
2479					}
2480					else
2481					{
2482						try
2483						{
2484							node[i] = node[i] + attributes[i];
2485						}
2486						catch(e){}
2487						node.setAttribute(i, node[i] + attributes[i]);
2488					}
2489				}
2490				break;
2491			}
2492			default:
2493			{
2494				for (var i in attributes)
2495				{
2496					//innerHTML hack bailout
2497					if(i == 'innerHTML')
2498					{
2499						HTML_AJAX_Util.setInnerHTML(node, attributes[i]);
2500					}
2501					else if(i == 'style')
2502					{
2503						var styles = [];
2504						if(attributes[i].indexOf(';'))
2505						{
2506							styles = attributes[i].split(';');
2507						}
2508						else
2509						{
2510							styles.push(attributes[i]);
2511						}
2512						for(var i = 0; i < styles.length; i++)
2513						{
2514							var r = styles[i].match(/^\s*(.+)\s*:\s*(.+)\s*$/);
2515							if(r)
2516							{
2517								node.style[this._camelize(r[1])] = r[2];
2518							}
2519						}
2520					}
2521					else
2522					{
2523						try
2524						{
2525							node[i] = attributes[i];
2526						}
2527						catch(e){}
2528						node.setAttribute(i, attributes[i]);
2529					}
2530				}
2531			}
2532		}
2533	}
2534}
2535// Loading.js
2536/**
2537 * Default loading implementation
2538 *
2539 * @category	HTML
2540 * @package	Ajax
2541 * @license	http://www.opensource.org/licenses/lgpl-license.php  LGPL
2542 * @copyright	2005 Joshua Eichorn
2543 * see Main.js for license Author details
2544 */
2545HTML_AJAX.Open = function(request) {
2546	var loading = document.getElementById('HTML_AJAX_LOADING');
2547	if (!loading) {
2548		loading = document.createElement('div');
2549		loading.id = 'HTML_AJAX_LOADING';
2550		loading.innerHTML = 'Loading...';
2551		
2552		loading.style.color	 = '#fff';
2553		loading.style.position  = 'absolute';
2554		loading.style.top   = 0;
2555		loading.style.right	 = 0;
2556		loading.style.backgroundColor = '#f00';
2557		loading.style.border		= '1px solid #f99';
2558		loading.style.width		 = '80px';
2559		loading.style.padding	   = '4px';
2560		loading.style.fontFamily	= 'Arial, Helvetica, sans';
2561		loading.count = 0;
2562	
2563		document.body.insertBefore(loading,document.body.firstChild);
2564	}
2565	else {
2566		if (loading.count == undefined) {
2567			loading.count = 0;
2568		}
2569	}
2570	loading.count++;
2571	if (request.isAsync) {
2572		request.loadingId = window.setTimeout(function() { loading.style.display = 'block'; },500);
2573	}
2574	else {
2575		loading.style.display = 'block';
2576	}
2577}
2578HTML_AJAX.Load = function(request) {
2579	if (request.loadingId) {
2580		window.clearTimeout(request.loadingId);
2581	}
2582	var loading = document.getElementById('HTML_AJAX_LOADING');
2583	loading.count--;
2584
2585	if (loading.count == 0) {
2586		loading.style.display = 'none';
2587	}
2588}
2589// util.js
2590/**
2591 * Utility methods
2592 *
2593 * @category	HTML
2594 * @package	Ajax
2595 * @license	http://www.opensource.org/licenses/lgpl-license.php  LGPL
2596 *
2597 * See Main.js for author/license details
2598 */
2599// {{{ HTML_AJAX_Util
2600/**
2601 * All the utilities we will be using thorough the classes
2602 */
2603var HTML_AJAX_Util = {
2604	// Set the element event
2605	registerEvent: function(element, event, handler) 
2606	{
2607		element = this.getElement(element);
2608		if (typeof element.addEventListener != "undefined") {   //Dom2
2609			element.addEventListener(event, handler, false);
2610		} else if (typeof element.attachEvent != "undefined") { //IE 5+
2611			element.attachEvent("on" + event, handler);
2612		} else {
2613			if (element["on" + event] != null) {
2614				var oldHandler = element["on" + event];
2615				element["on" + event] = function(e) {
2616					oldHander(e);
2617					handler(e);
2618				};
2619			} else {
2620				element["on" + event] = handler;
2621			}
2622		}
2623	},
2624	// get the target of an event, automatically checks window.event for ie
2625	eventTarget: function(event) 
2626	{
2627		if (!event) var event = window.event;
2628		if (event.target) return event.target; // w3c
2629		if (event.srcElement) return event.srcElement; // ie 5
2630	},
2631	// gets the type of a variable or its primitive equivalent as a string
2632	getType: function(inp) 
2633	{
2634		var type = typeof inp, match;
2635		if(type == 'object' && !inp)
2636		{
2637			return 'null';
2638		}
2639		if (type == "object") {
2640			if(!inp.constructor)
2641			{
2642				return 'object';
2643			}
2644			var cons = inp.constructor.toString();
2645			if (match = cons.match(/(\w+)\(/)) {
2646				cons = match[1].toLowerCase();
2647			}
2648			var types = ["boolean", "number", "string", "array"];
2649			for (key in types) {
2650				if (cons == types[key]) {
2651					type = types[key];
2652					break;
2653				}
2654			}
2655		}
2656		return type;
2657	},
2658	// repeats the input string the number of times given by multiplier. exactly like PHP's str_repeat()
2659	strRepeat: function(inp, multiplier) {
2660		var ret = "";
2661		while (--multiplier > 0) ret += inp;
2662		return ret;
2663	},
2664	// encode a string allowing it to be used in a query string of a url
2665	encodeUrl: function(input) {
2666		return encodeURIComponent(input);
2667	},
2668	// decode a url encoded string
2669	decodeUrl: function(input) {
2670		return decodeURIComponent(input);
2671	},
2672	// recursive variable dumper similar in output to PHP's var_dump(), the differences being: this function displays JS types and type names; JS doesn't provide an object number like PHP does
2673	varDump: function(inp, printFuncs, _indent, _recursionLevel)
2674	{
2675		if (!_recursionLevel) _recursionLevel = 0;
2676		if (!_indent) _indent = 1;
2677		var tab = this.strRepeat("  ", ++_indent);	
2678		var type = this.getType(inp), out = type;
2679		var consrx = /(\w+)\(/;
2680		consrx.compile();
2681		if (++_recursionLevel > 6) {
2682			return tab + inp + "Loop Detected\n";
2683		}
2684		switch (type) {
2685			case "boolean":
2686			case "number":
2687				out += "(" + inp.toString() + ")";
2688				break;
2689			case "string":
2690				out += "(" + inp.length + ") \"" + inp + "\"";
2691				break;
2692			case "function":
2693				if (printFuncs) {
2694					out += inp.toString().replace(/\n/g, "\n" + tab);
2695				}
2696				break;
2697			case "array":
2698			case "object":
2699				var atts = "", attc = 0;
2700				try {
2701					for (k in inp) {
2702						atts += tab + "[" + (/\D/.test(k) ? "\"" + k + "\"" : k)
2703							+ "]=>\n" + tab + this.varDump(inp[k], printFuncs, _indent, _recursionLevel);
2704						++attc;
2705					}
2706				} catch (e) {}
2707				if (type == "object") {
2708					var objname, objstr = inp.toString();
2709					if (objname = objstr.match(/^\[object (\w+)\]$/)) {
2710						objname = objname[1];
2711					} else {
2712						try {
2713							objname = inp.constructor.toString().match(consrx)[1];
2714						} catch (e) {
2715							objname = 'unknown';
2716						}
2717					}
2718					out += "(" + objname + ") ";
2719				}
2720				out += "(" + attc + ") {\n" + atts + this.strRepeat("  ", _indent - 1) +"}";
2721				break;
2722		}
2723		return out + "\n";
2724	},
2725	// non resursive simple debug printer
2726	quickPrint: function(input,sep) {
2727		if (!sep) {
2728			var sep = "\n";
2729		}
2730		var type = HTML_AJAX_Util.getType(input);
2731		switch (type) {
2732			case 'string':
2733				return input;
2734			case 'array':
2735				var ret = "";
2736				for(var i = 0; i < input.length; i++) {
2737					ret += i+':'+input[i]+sep;
2738				}
2739				return ret;
2740			default:
2741				var ret = "";
2742				for(var i in input) {
2743					ret += i+':'+input[i]+sep;
2744				}
2745				return ret;
2746		}
2747	},
2748	//compat function for stupid browsers in which getElementsByTag with a * dunna work
2749	getAllElements: function(parentElement)
2750	{
2751		//check for idiot browsers
2752		if( document.all)
2753		{
2754			if(!parentElement) {
2755				var allElements = document.all;
2756			}
2757			else
2758			{
2759				var allElements = [], rightName = new RegExp( parentElement, 'i' ), i;
2760				for( i=0; i<document.all.length; i++ ) {
2761					if( rightName.test( document.all[i].parentElement ) )
2762					allElements.push( document.all[i] );
2763				}
2764			}
2765			return allElements;
2766		}
2767		//real browsers just do this
2768		else
2769		{
2770			if (!parentElement) { parentElement = document.body; }
2771			return parentElement.getElementsByTagName('*');
2772		}
2773	},
2774	getElementsByProperty: function(property, regex, parentElement) {
2775		var allElements = HTML_AJAX_Util.getAllElements(parentElement);
2776		var items = [];
2777		for(var i=0,j=allElements.length; i<j; i++)
2778		{
2779			if(regex.test(allElements[i][property]))
2780			{
2781				items.push(allElements[i]);
2782			}
2783		}
2784		return items;
2785	},
2786	getElementsByClassName: function(className, parentElement) {
2787		return HTML_AJAX_Util.getElementsByProperty('className',new RegExp('(^| )' + className + '( |$)'),parentElement);
2788	},
2789	getElementsById: function(id, parentElement) {
2790		return HTML_AJAX_Util.getElementsByProperty('id',new RegExp(id),parentElement);
2791	},
2792	getElementsByCssSelector: function(selector,parentElement) {
2793		return cssQuery(selector,parentElement);
2794	},
2795	htmlEscape: function(inp) {
2796		var div = document.createElement('div');
2797		var text = document.createTextNode(inp);
2798		div.appendChild(text);
2799		return div.innerHTML;
2800	},
2801	// return the base of the given absolute url, or the filename if the second argument is true
2802	baseURL: function(absolute, filename) {
2803		var qPos = absolute.indexOf('?');
2804		if (qPos >= 0) {
2805			absolute = absolute.substr(0, qPos);
2806		}
2807		var slashPos = Math.max(absolute.lastIndexOf('/'), absolute.lastIndexOf('\\'));
2808		if (slashPos < 0) {
2809			return absolute;
2810		}
2811		return (filename ? absolute.substr(slashPos + 1) : absolute.substr(0, slashPos + 1));
2812	},
2813	// return the query string from a url
2814	queryString: function(url) {
2815		var qPos = url.indexOf('?');
2816		if (qPos >= 0) {
2817			return url.substr(qPos+1);
2818		}
2819	},
2820	// return the absolute path to the given relative url
2821	absoluteURL: function(rel, absolute) {
2822		if (/^https?:\/\//i.test(rel)) {
2823			return rel;
2824		}
2825		if (!absolute) {
2826			var bases = document.getElementsByTagName('base');
2827			for (i in bases) {
2828				if (bases[i].href) {
2829					absolute = bases[i].href;
2830					break;
2831				}
2832			}
2833			if (!absolute) {
2834				absolute = window.location.href;
2835			}
2836		}
2837		if (rel == '') {
2838			return absolute;
2839		}
2840		if (rel.substr(0, 2) == '//') {
2841			// starts with '//', replace everything but the protocol
2842			var slashesPos = absolute.indexOf('//');
2843			if (slashesPos < 0) {
2844				return 'http:' + rel;
2845			}
2846			return absolute.substr(0, slashesPos) + rel;
2847		}
2848		var base = this.baseURL(absolute);
2849		var absParts = base.substr(0, base.length - 1).split('/');
2850		var absHost = absParts.slice(0, 3).join('/') + '/';
2851		if (rel.substr(0, 1) == '/') {
2852			// starts with '/', append it to the host
2853			return absHost + rel;
2854		}
2855		if (rel.substr(0, 1) == '.' && rel.substr(1, 1) != '.') {
2856			// starts with '.', append it to the base
2857			return base + rel.substr(1);
2858		}
2859		// remove everything upto the path and beyond 
2860		absParts.splice(0, 3);
2861		var relParts = rel.split('/');
2862		var loopStart = relParts.length - 1;
2863		relParts = absParts.concat(relParts);
2864		for (i = loopStart; i < relParts.length;) {
2865			if (relParts[i] == '..') {
2866				if (i == 0) {
2867					return absolute;
2868				}
2869				relParts.splice(i - 1, 2);
2870				--i;
2871				continue;
2872			}
2873			i++;
2874		}
2875		return absHost + relParts.join('/');
2876	},
2877	// sets the innerHTML of an element. the third param decides how to write, it replaces by default, others are append|prepend
2878	setInnerHTML: function(node, innerHTML, type)
2879	{
2880		node = this.getElement(node);
2881
2882		if (type != 'append') {
2883			if (type == 'prepend') {
2884				var oldHtml = node.innerHTML;
2885			}
2886			node.innerHTML = '';
2887		}
2888		var good_browser = (navigator.product == 'Gecko');
2889		var regex = /^([\s\S]*?)<script([\s\S]*?)>([\s\S]*?)<\/script>([\s\S]*)$/i;
2890		var regex_src = /src=["'](.*?)["']/i;
2891		var matches, id, script, output = '', subject = innerHTML;
2892		var scripts = [];
2893
2894		while (true) {
2895			matches = regex.exec(subject);
2896			if (matches && matches[0]) {
2897				subject = matches[4];
2898				id = 'ih_' + Math.round(Math.random()*9999) + '_' + Math.round(Math.random()*9999);
2899
2900				var startLen = matches[3].length;
2901				script = matches[3].replace(/document\.write\(([\s\S]*?)\)/ig, 
2902					'document.getElementById("' + id + '").innerHTML+=$1');
2903
2904				output += matches[1];
2905				if (startLen != script.length) {
2906						output += '<span id="' + id + '"></span>';
2907				}
2908				
2909				output += '<script' + matches[2] + '>
2909' + script + '</script>';
2910				if (good_browser) {
2911					continue;
2912				}
2913				if (script) {
2914					scripts.push(script);
2915				}
2916				if (regex_src.test(matches[2])) {
2917					var script_el = document.createElement("SCRIPT");
2918					var atts_regex = /(\w+)=["'](.*?)["']([\s\S]*)$/;
2919					var atts = matches[2];
2920					for (var i = 0; i < 5; i++) { 
2921						var atts_matches = atts_regex.exec(atts);
2922						if (atts_matches && atts_matches[0]) {
2923							script_el.setAttribute(atts_matches[1], atts_matches[2]);
2924							atts = atts_matches[3];
2925						} else {
2926							break;
2927						}
2928					}
2929					scripts.push(script_el);
2930				}
2931			} else {
2932				output += subject;
2933				break;
2934			}
2935		}
2936		innerHTML = output;
2937
2938		if (good_browser) {
2939			var el = document.createElement('span');
2940			el.innerHTML = innerHTML;
2941
2942			for(var i = 0; i < el.childNodes.length; i++) {
2943				node.appendChild(el.childNodes[i].cloneNode(true));
2944			}
2945		}
2946		else {
2947			node.innerHTML += innerHTML;
2948		}
2949
2950		if (oldHtml) {
2951			node.innerHTML += oldHtml;
2952		}
2953
2954		if (!good_browser) {
2955			for(var i = 0; i < scripts.length; i++) {
2956				if (HTML_AJAX_Util.getType(scripts[i]) == 'string') {
2957					scripts[i] = scripts[i].replace(/^\s*<!(\[CDATA\[|--)|((\/\/)?--|\]\])>\s*$/g, '');
2958					window.eval(scripts[i]);
2959				}
2960				else {
2961					node.appendChild(scripts[i]);
2962				}
2963			}
2964		}
2965		return;
2966	},
2967	classSep: '(^|$| )',
2968	hasClass: function(o, className) {
2969		var o = this.getElement(o);
2970		var regex = new RegExp(this.classSep + className + this.classSep);
2971		return regex.test(o.className);
2972	},
2973	addClass: function(o, className) {
2974		var o = this.getElement(o);
2975		if(!this.hasClass(o, className)) {
2976			o.className += " " + className;
2977		}
2978	},
2979	removeClass: function(o, className) {
2980		var o = this.getElement(o);
2981		var regex = new RegExp(this.classSep + className + this.classSep);
2982		o.className = o.className.replace(regex, " ");
2983	},
2984	replaceClass: function(o, oldClass, newClass) {
2985		var o = this.getElement(o);
2986		var regex = new RegExp(this.classSep + oldClass + this.classSep);
2987		o.className = o.className.replace(regex, newClass);
2988	},
2989	getElement: function(el) {
2990		if (typeof el == 'string') {
2991			return document.getElementById(el);
2992		}
2993		return el;
2994	}
2995}
2996// }}}
2997// behavior/behavior.js
2998/**
2999
3000ModifiedBehavior v1.0 by Ron Lancaster based on Ben Nolan's Behaviour, June 2005 implementation.
3001Modified to use Dean Edward's CSS Query.
3002
3003Description
3004----------
3005
3006Uses css selectors  to apply javascript Behaviors to enable unobtrusive javascript in html documents.
3007
3008Dependencies
3009------------
3010
3011Requires [Dean Edwards CSSQuery](http://dean.edwards.name/my/cssQuery/ "CSSQuery").
3012
3013Usage
3014------
3015
3016		Behavior.register(
3017			"b.someclass",
3018			function(element) {
3019				element.onclick = function(){
3020					alert(this.innerHTML);
3021				}
3022			}
3023		);
3024
3025		Behavior.register(
3026			"#someid u",
3027			function(element) {
3028				element.onmouseover = function(){
3029					this.innerHTML = "BLAH!";
3030				}
3031			},
3032			getElementByID("parent")
3033		);
3034
3035Call `Behavior.apply()` to re-apply the rules (if you update the dom, etc).
3036
3037License
3038------
3039
3040Reproduced under BSD licensed. Same license as Ben Nolan's implementation.
3041
3042More information for Ben Nolan's implementation: <http://ripcord.co.nz/behaviour/>
3043
3044*/
3045
3046var Behavior = {
3047	// so to an id to get debug timings
3048	debug : false,
3049
3050	// private data member
3051	list : new Array(),
3052
3053	// private method
3054	addLoadEvent : function(func) {
3055		var oldonload = window.onload;
3056
3057		if (typeof window.onload != 'function') {
3058			window.onload = func;
3059		} else {
3060			window.onload = function() {
3061				oldonload();
3062				func();
3063			}
3064		}
3065	},
3066
3067	// void apply() : Applies the registered ruleset.
3068	apply : function() {
3069		if (this.debug) {
3070			document.getElementById(this.debug).innerHTML += 'Apply: '+new Date()+'<br>';
3071			var total = 0;
3072		}
3073		if (Behavior.list.length > 2) {
3074			cssQuery.caching = true;
3075		}
3076		for (i = 0; i < Behavior.list.length; i++) {
3077			var rule = Behavior.list[i];
3078			
3079			if (this.debug) { var ds = new Date() };
3080			var tags = cssQuery(rule.selector, rule.from);
3081	
3082			if (this.debug) {
3083				var de = new Date();
3084				var ts = de.valueOf()-ds.valueOf();
3085				document.getElementById(this.debug).innerHTML += 'Rule: '+rule.selector+' - Took: '+ts+' - Returned: '+tags.length+' tags<br>';
3086				total += ts;
3087			}
3088			if (tags) {
3089				for (j = 0; j < tags.length; j++) {
3090					rule.action(tags[j]);
3091				}
3092			}
3093		}
3094		if (Behavior.list.length > 2) {
3095			cssQuery.caching = false;
3096		}
3097
3098		if (this.debug) {
3099			document.getElementById(this.debug).innerHTML += 'Total rule apply time: '+total;
3100		}
3101	},
3102
3103	// void register() : register a css selector, and the action (function) to take,
3104	// from (optional) is a document, element or array of elements which is filtered by selector.
3105	register : function(selector, action, from) {
3106		Behavior.list.push(new BehaviorRule(selector, from, action));
3107	},
3108
3109	// void start() : initial application of ruleset at document load.
3110	start : function() {
3111		Behavior.addLoadEvent(function() {
3112			Behavior.apply();
3113		});
3114	}
3115}
3116
3117function BehaviorRule(selector, from, action) {
3118	this.selector = selector;
3119	this.from = from;
3120	this.action = action;
3121}
3122
3123Behavior.start();
3124// behavior/cssQuery-p.js
3125/*
3126	cssQuery, version 2.0.2 (2005-08-19)
3127	Copyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)
3128	License: http://creativecommons.org/licenses/LGPL/2.1/
3129*/
3130eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('7 x=6(){7 1D="2.0.2";7 C=/\\s*,\\s*/;7 x=6(s,A){33{7 m=[];7 u=1z.32.2c&&!A;7 b=(A)?(A.31==22)?A:[A]:[1g];7 1E=18(s).1l(C),i;9(i=0;i<1E.y;i++){s=1y(1E[i]);8(U&&s.Z(0,3).2b("")==" *#"){s=s.Z(2);A=24([],b,s[1])}1A A=b;7 j=0,t,f,a,c="";H(j<s.y){t=s[j++];f=s[j++];c+=t+f;a="";8(s[j]=="("){H(s[j++]!=")")a+=s[j];a=a.Z(0,-1);c+="("+a+")"}A=(u&&V[c])?V[c]:21(A,t,f,a);8(u)V[c]=A}m=m.30(A)}2a x.2d;5 m}2Z(e){x.2d=e;5[]}};x.1Z=6(){5"6 x() {\\n  [1D "+1D+"]\\n}"};7 V={};x.2c=L;x.2Y=6(s){8(s){s=1y(s).2b("");2a V[s]}1A V={}};7 29={};7 19=L;x.15=6(n,s){8(19)1i("s="+1U(s));29[n]=12 s()};x.2X=6(c){5 c?1i(c):o};7 D={};7 h={};7 q={P:/\\[([\\w-]+(\\|[\\w-]+)?)\\s*(\\W?=)?\\s*([^\\]]*)\\]/};7 T=[];D[" "]=6(r,f,t,n){7 e,i,j;9(i=0;i<f.y;i++){7 s=X(f[i],t,n);9(j=0;(e=s[j]);j++){8(M(e)&&14(e,n))r.z(e)}}};D["#"]=6(r,f,i){7 e,j;9(j=0;(e=f[j]);j++)8(e.B==i)r.z(e)};D["."]=6(r,f,c){c=12 1t("(^|\\\\s)"+c+"(\\\\s|$)");7 e,i;9(i=0;(e=f[i]);i++)8(c.l(e.1V))r.z(e)};D[":"]=6(r,f,p,a){7 t=h[p],e,i;8(t)9(i=0;(e=f[i]);i++)8(t(e,a))r.z(e)};h["2W"]=6(e){7 d=Q(e);8(d.1C)9(7 i=0;i<d.1C.y;i++){8(d.1C[i]==e)5 K}};h["2V"]=6(e){};7 M=6(e){5(e&&e.1c==1&&e.1f!="!")?e:23};7 16=6(e){H(e&&(e=e.2U)&&!M(e))28;5 e};7 G=6(e){H(e&&(e=e.2T)&&!M(e))28;5 e};7 1r=6(e){5 M(e.27)||G(e.27)};7 1P=6(e){5 M(e.26)||16(e.26)};7 1o=6(e){7 c=[];e=1r(e);H(e){c.z(e);e=G(e)}5 c};7 U=K;7 1h=6(e){7 d=Q(e);5(2S d.25=="2R")?/\\.1J$/i.l(d.2Q):2P(d.25=="2O 2N")};7 Q=6(e){5 e.2M||e.1g};7 X=6(e,t){5(t=="*"&&e.1B)?e.1B:e.X(t)};7 17=6(e,t,n){8(t=="*")5 M(e);8(!14(e,n))5 L;8(!1h(e))t=t.2L();5 e.1f==t};7 14=6(e,n){5!n||(n=="*")||(e.2K==n)};7 1e=6(e){5 e.1G};6 24(r,f,B){7 m,i,j;9(i=0;i<f.y;i++){8(m=f[i].1B.2J(B)){8(m.B==B)r.z(m);1A 8(m.y!=23){9(j=0;j<m.y;j++){8(m[j].B==B)r.z(m[j])}}}}5 r};8(![].z)22.2I.z=6(){9(7 i=0;i<1z.y;i++){o[o.y]=1z[i]}5 o.y};7 N=/\\|/;6 21(A,t,f,a){8(N.l(f)){f=f.1l(N);a=f[0];f=f[1]}7 r=[];8(D[t]){D[t](r,A,f,a)}5 r};7 S=/^[^\\s>+~]/;7 20=/[\\s#.:>+~()@]|[^\\s#.:>+~()@]+/g;6 1y(s){8(S.l(s))s=" "+s;5 s.P(20)||[]};7 W=/\\s*([\\s>+~(),]|^|$)\\s*/g;7 I=/([\\s>+~,]|[^(]\\+|^)([#.:@])/g;7 18=6(s){5 s.O(W,"$1").O(I,"$1*$2")};7 1u={1Z:6(){5"\'"},P:/^(\'[^\']*\')|("[^"]*")$/,l:6(s){5 o.P.l(s)},1S:6(s){5 o.l(s)?s:o+s+o},1Y:6(s){5 o.l(s)?s.Z(1,-1):s}};7 1s=6(t){5 1u.1Y(t)};7 E=/([\\/()[\\]?{}|*+-])/g;6 R(s){5 s.O(E,"\\\\$1")};x.15("1j-2H",6(){D[">"]=6(r,f,t,n){7 e,i,j;9(i=0;i<f.y;i++){7 s=1o(f[i]);9(j=0;(e=s[j]);j++)8(17(e,t,n))r.z(e)}};D["+"]=6(r,f,t,n){9(7 i=0;i<f.y;i++){7 e=G(f[i]);8(e&&17(e,t,n))r.z(e)}};D["@"]=6(r,f,a){7 t=T[a].l;7 e,i;9(i=0;(e=f[i]);i++)8(t(e))r.z(e)};h["2G-10"]=6(e){5!16(e)};h["1x"]=6(e,c){c=12 1t("^"+c,"i");H(e&&!e.13("1x"))e=e.1n;5 e&&c.l(e.13("1x"))};q.1X=/\\\\:/g;q.1w="@";q.J={};q.O=6(m,a,n,c,v){7 k=o.1w+m;8(!T[k]){a=o.1W(a,c||"",v||"");T[k]=a;T.z(a)}5 T[k].B};q.1Q=6(s){s=s.O(o.1X,"|");7 m;H(m=s.P(o.P)){7 r=o.O(m[0],m[1],m[2],m[3],m[4]);s=s.O(o.P,r)}5 s};q.1W=6(p,t,v){7 a={};a.B=o.1w+T.y;a.2F=p;t=o.J[t];t=t?t(o.13(p),1s(v)):L;a.l=12 2E("e","5 "+t);5 a};q.13=6(n){1d(n.2D()){F"B":5"e.B";F"2C":5"e.1V";F"9":5"e.2B";F"1T":8(U){5"1U((e.2A.P(/1T=\\\\1v?([^\\\\s\\\\1v]*)\\\\1v?/)||[])[1]||\'\')"}}5"e.13(\'"+n.O(N,":")+"\')"};q.J[""]=6(a){5 a};q.J["="]=6(a,v){5 a+"=="+1u.1S(v)};q.J["~="]=6(a,v){5"/(^| )"+R(v)+"( |$)/.l("+a+")"};q.J["|="]=6(a,v){5"/^"+R(v)+"(-|$)/.l("+a+")"};7 1R=18;18=6(s){5 1R(q.1Q(s))}});x.15("1j-2z",6(){D["~"]=6(r,f,t,n){7 e,i;9(i=0;(e=f[i]);i++){H(e=G(e)){8(17(e,t,n))r.z(e)}}};h["2y"]=6(e,t){t=12 1t(R(1s(t)));5 t.l(1e(e))};h["2x"]=6(e){5 e==Q(e).1H};h["2w"]=6(e){7 n,i;9(i=0;(n=e.1F[i]);i++){8(M(n)||n.1c==3)5 L}5 K};h["1N-10"]=6(e){5!G(e)};h["2v-10"]=6(e){e=e.1n;5 1r(e)==1P(e)};h["2u"]=6(e,s){7 n=x(s,Q(e));9(7 i=0;i<n.y;i++){8(n[i]==e)5 L}5 K};h["1O-10"]=6(e,a){5 1p(e,a,16)};h["1O-1N-10"]=6(e,a){5 1p(e,a,G)};h["2t"]=6(e){5 e.B==2s.2r.Z(1)};h["1M"]=6(e){5 e.1M};h["2q"]=6(e){5 e.1q===L};h["1q"]=6(e){5 e.1q};h["1L"]=6(e){5 e.1L};q.J["^="]=6(a,v){5"/^"+R(v)+"/.l("+a+")"};q.J["$="]=6(a,v){5"/"+R(v)+"$/.l("+a+")"};q.J["*="]=6(a,v){5"/"+R(v)+"/.l("+a+")"};6 1p(e,a,t){1d(a){F"n":5 K;F"2p":a="2n";1a;F"2o":a="2n+1"}7 1m=1o(e.1n);6 1k(i){7 i=(t==G)?1m.y-i:i-1;5 1m[i]==e};8(!Y(a))5 1k(a);a=a.1l("n");7 m=1K(a[0]);7 s=1K(a[1]);8((Y(m)||m==1)&&s==0)5 K;8(m==0&&!Y(s))5 1k(s);8(Y(s))s=0;7 c=1;H(e=t(e))c++;8(Y(m)||m==1)5(t==G)?(c<=s):(s>=c);5(c%m)==s}});x.15("1j-2m",6(){U=1i("L;/*@2l@8(@\\2k)U=K@2j@*/");8(!U){X=6(e,t,n){5 n?e.2i("*",t):e.X(t)};14=6(e,n){5!n||(n=="*")||(e.2h==n)};1h=1g.1I?6(e){5/1J/i.l(Q(e).1I)}:6(e){5 Q(e).1H.1f!="2g"};1e=6(e){5 e.2f||e.1G||1b(e)};6 1b(e){7 t="",n,i;9(i=0;(n=e.1F[i]);i++){1d(n.1c){F 11:F 1:t+=1b(n);1a;F 3:t+=n.2e;1a}}5 t}}});19=K;5 x}();',62,190,'|||||return|function|var|if|for||||||||pseudoClasses||||test|||this||AttributeSelector|||||||cssQuery|length|push|fr|id||selectors||case|nextElementSibling|while||tests|true|false|thisElement||replace|match|getDocument|regEscape||attributeSelectors|isMSIE|cache||getElementsByTagName|isNaN|slice|child||new|getAttribute|compareNamespace|addModule|previousElementSibling|compareTagName|parseSelector|loaded|break|_0|nodeType|switch|getTextContent|tagName|document|isXML|eval|css|_1|split|ch|parentNode|childElements|nthChild|disabled|firstElementChild|getText|RegExp|Quote|x22|PREFIX|lang|_2|arguments|else|all|links|version|se|childNodes|innerText|documentElement|contentType|xml|parseInt|indeterminate|checked|last|nth|lastElementChild|parse|_3|add|href|String|className|create|NS_IE|remove|toString|ST|select|Array|null|_4|mimeType|lastChild|firstChild|continue|modules|delete|join|caching|error|nodeValue|textContent|HTML|prefix|getElementsByTagNameNS|end|x5fwin32|cc_on|standard||odd|even|enabled|hash|location|target|not|only|empty|root|contains|level3|outerHTML|htmlFor|class|toLowerCase|Function|name|first|level2|prototype|item|scopeName|toUpperCase|ownerDocument|Document|XML|Boolean|URL|unknown|typeof|nextSibling|previousSibling|visited|link|valueOf|clearCache|cat
3130ch|concat|constructor|callee|try'.split('|'),0,{}))

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.