PageSourceSearch

https://static.nintendolife.com/js/ccms.js?v=1652429866

js nintendolife.com collected 2026-09-24 08:37:50 UTC 89,132 bytes, 3,031 lines download raw bytes

1var ccms = window.ccms || {};
2
3ccms.hasOwnProperty = (Object.prototype.hasOwnProperty) ? function(o, prop) {return o && o.hasOwnProperty(prop);}
4														: function(o, prop) {return typeof o[prop] !== 'undefined' && o.constructor.prototype[prop] !== o[prop];};
5
6// object inheritance/extension utility function. http://javascript.crockford.com/prototypal.html
7ccms.object = function(o) {
8	function F() {}
9	F.prototype = o;
10	return new F();
11};
12
13// array update / merge function
14ccms.extend = ccms.update = function(destination, source) {
15	for (var property in source) {
16		if (ccms.hasOwnProperty(source, property)) {
17			destination[property] = source[property];
18		}
19	}
20	return destination;
21};
22
23// clone an object (shallow clone). usage: var clone = ccms.cloneOf(thing);
24ccms.cloneOf = function(what) {
25	var i, o;
26	if (typeof what.prototype == 'undefined') {
27		o = {};
28		for (i in what) {
29			o[i] = what[i];
30		}
31	}
32	else {
33		o = ccms.object(what.prototype);
34		for (i in what) {
35			if (ccms.hasOwnProperty(what, i)) {
36				o[i] = what[i];
37			}
38		}
39	}
40	return o;
41};
42
43ccms.namespace = function(name) {
44	if (!name || !name.length) {
45		return null;
46	}
47	var parts = name.split(".");
48	var ns = window;
49	for (var i = 0; i < parts.length; ++i) {
50		ns[parts[i]] = ns[parts[i]] || {};
51 		ns = ns[parts[i]];
52	}
53	return ns;
54};
55
56// Asynchronous operations (http, timed events)
57ccms.namespace('ccms.async');
58// Configuration
59ccms.namespace('ccms.config');
60// DOM helper functions
61ccms.namespace('ccms.dom');
62// Event library
63ccms.namespace('ccms.event');
64// Logging / Messages
65ccms.namespace('ccms.log');
66// CSS helper functions
67ccms.namespace('ccms.css');
68// Date utilities
69ccms.namespace('ccms.date');
70
71ccms.extend(ccms, (function() {
72	var scripts = [];
73	return {
74
75		detectScripts: function(evt) {
76			var src;
77			var stags = ccms.arrayOf(document.getElementsByTagName('script'));
78			for (var t = 0; t < stags.length; ++t) {
79				if ((src = stags[t].getAttribute('src')) && src.length) {
80					src = src.replace(/\?v=[0-9]+/,'');
81					scripts[src] = true;
82				}
83			}
84		},
85		
86		// jscombo'd scripts call this with each contained url
87		addScript: function(url) {
88			url = url.replace(/\?v=[0-9]+/,'');
89			scripts[url] = true;
90		},
91		
92		// import an external script
93		require: function(url, callback) {
94			if (!url) return false;
95			var s = false;
96			var src = url.replace(/\?v=[0-9]+/,'');
97			if (typeof scripts[src] === 'undefined') {
98				scripts[src] = true;
99				if (navigator.userAgent.indexOf('MSIE') > 0) {
100					ccms.require_sync(url);
101				}
102				else {
103					s = document.createElement('script');
104					s.setAttribute('type', 'text/javascript');
105					s.setAttribute('src', url);
106					document.getElementsByTagName('head')[0].appendChild(s);
107				}
108			}
109
110			if (typeof callback === 'function') {
111				if (s) {
112					// Tested:
113					// - Firefox (y)
114					// - Safari  (n)
115					ccms.event.attach(s, 'load', function() { callback(); });
116				}
117				else {
118					callback();
119				}
120			}
121
122			return scripts[url];
123		},
124
125		require_sync: function(url) {
126			var script = ccms.async.http({
127				url:url
128			});
129			window.eval(script);
130		},
131		
132		browser: {
133			isIE: /*@cc_on!@*/false,
134			isSafari: /webkit/gi.test(navigator.userAgent),
135			isWebKit: /webkit/gi.test(navigator.userAgent),
136			isGecko: !(/webkit/gi.test(navigator.userAgent)) && (/Gecko/.test(navigator.userAgent))
137		},
138		
139		
140		push: function(a, value) {a[a.length] = value;},
141		
142		indexOf: function(a, item) {
143			for (var i = 0; i < a.length; ++i) {
144				if (a[i] === item) {
145					return i;
146				}
147			}
148			return -1;
149		},
150		
151		// array filter function
152		filter: function(a, callback) {
153			if (!callback) {
154				callback = function(e) {return e;};
155			}
156			var out = [];
157			for (var i = 0; i < a.length; ++i) {
158				if (callback(a[i])) {
159					out[out.length] = a[i];
160				}
161			}
162			return out;
163		},
164		// array map function
165		map: function(a, callback) {
166			if (!callback) {
167				callback = function(e) {return e;};
168			}
169			var out = [];
170			for (var i in a) {
171				if (ccms.hasOwnProperty(a, i)) {
172					out[i] = callback(a[i]);
173				}
174			}
175			return out;
176		},
177		// array membership function
178		contains: function(a, value) {
179			for (var i in a) {
180				if (ccms.hasOwnProperty(a, i) && a[i] === value) {
181					return true;
182				}
183			}
184			return false;
185		},
186		
187		containsi: function(a, value) {
188			var valuei = value.toLowerCase();
189			for (var i in a) {
190				if (ccms.hasOwnProperty(a, i) && (((typeof a[i] === 'string') && (a[i].toLowerCase() === valuei)) || (a[i] === value))) {
191					return true;
192				}
193			}
194			return false;
195		},
196		
197		remove: function(a, value) {
198			for (var i in a) {
199				if (ccms.hasOwnProperty(a, i) && a[i] === value) {
200					delete a[i];
201				}
202			}
203			return a;
204		},
205		
206		removei: function(a, value) {
207			var valuei = value.toLowerCase();
208			for (var i in a) {
209				if (ccms.hasOwnProperty(a, i) && (((typeof a[i] === 'string') && (a[i].toLowerCase() === valuei)) || (a[i] === value))) {
210					delete a[i];
211				}
212			}
213			return a;
214		},
215		
216		flip: function(a) {
217			var b = [];
218			for(var i in a) {
219				if (ccms.hasOwnProperty(a, i)) {
220					b[a[i]] = i;
221				}
222			}
223			return b;
224		},
225		
226		shift: function(a) {
227			var result = a[0];
228			for (var i = 0; i < a.length - 1; ++i) {
229				a[i] = a[i + 1];
230			}
231			--a.length;
232			return result;
233		},
234		
235		keysOf: function(object) {
236			var r = [];
237			for (var i in object) {
238				if (ccms.hasOwnProperty(object, i)) {
239					r[r.length] = i;
240				}
241			}
242			return r;
243		},
244		
245		valuesOf: function(object) {
246			var r = [];
247			for (var i in object) {
248				if (ccms.hasOwnProperty(object, i)) {
249					r[r.length] = object[i];
250				}
251			}
252			return r;
253		},
254		
255		arrayOf: function(iterable) {
256			var results = [];
257			if (!iterable) {return results;}
258			if (iterable.toArray) {
259				return iterable.toArray();
260			}
261			else {
262				for (var i = 0; i < iterable.length; i++) {
263					results[results.length] = iterable[i];
264				}
265				return results;
266			}
267		},
268		
269		isCollection: function(o) {
270			return (
271				o						&& // o is something
272				o.length				&& // o is indexed
273				(typeof o !== "string")	&& // o is not a string
274				!o.tagName				&& // o is not an HTML element
275				!o.alert				&& // o is not a window
276				(typeof o[0] !== "undefined")
277			);
278		},
279
280		bind: function(obj, method) {
281			return function() {
282				var args = arguments;
283				return method.apply(obj, args);
284			};
285		},
286		
287		chain: function(f1, f2) {
288			if (f1) {
289				if (f2) {
290					return function() {f1(); return f2();};
291				}
292				return f1;
293			}
294			return f2;
295		},
296		
297		html: {
298			isAvailable: false,
299			isWanted: false,
300			use: function() {
301                ccms.html.isAvailable = true;
302                ccms.html.isWanted = true;
303                ccms.html = ccms.DomBuilder.apply(ccms.html);
304                ccms.html.use = function() {};
305			}
306		},
307
308		widgets: {
309			widgetlist: [],
310			installers: {},
311			add: function(widget, id) {
312				if (typeof id !== 'string' || id === '') {
313					id = ccms.widgets.widgetlist.length;
314				}
315				if (ccms.widgets.widgetlist[id]) {
316					id = ccms.dom.generateId();
317				}
318				ccms.widgets.widgetlist[id] = widget;
319			},
320			get: function(id) {
321				return ccms.widgets.widgetlist[id];
322			},
323			remove: function(id) {
324				delete ccms.widgets.widgetlist[id];
325			},
326			each: function(callback) {
327				for(var i in ccms.widgets.widgetlist) {
328					if (ccms.hasOwnProperty(ccms.widgets.widgetlist, i)) {
329						callback(ccms.widgets.widgetlist[i]);
330					}
331				}
332			},
333			addInstaller: function(name, callback, condition) {
334				ccms.widgets.installers[name] = callback;
335				
336				if (condition !== false) {
337					if (typeof condition === 'undefined') {
338						if (ccms.dom.ready) {
339							callback();
340						}
341						else {
342							ccms.event.onDOMReady(function() {callback();}); // wrap function cos onDOMReady passes parameters
343						}
344						return;
345					}
346					if (!ccms.dom.ready) { // Queue for later
347						ccms.event.addLoadEvent(function() { ccms.async.when(condition, callback); });
348					}
349					else { // Call Now
350						ccms.async.when(condition, callback);
351					}
352				}
353			},
354			runInstallers: function(block, optional_data) {
355				if (typeof block === 'undefined') {
356					block = document;
357				}
358				else if (block.target || block.srcElement) {
359					// Event Got This
360					block = document;
361				}
362				
363				var funx = ccms.widgets.installers;
364				for (var name in funx) {
365					if (ccms.hasOwnProperty(funx, name)) {
366						funx[name](block, optional_data);
367					}
368				}
369
370				return block;
371			},
372
373			addClassInstaller: function(WidgetConstructor, classname, tagname) {
374				var name = classname;
375				var i = 1;
376				while (name in ccms.widgets.installers) {
377					name = classname + (++i);
378				}
379				ccms.widgets.addInstaller(name,
380					ccms.widgets.installNow.partial(WidgetConstructor, classname, tagname)
381				);
382			},
383			
384			removeInstaller: function(name) {
385				delete ccms.widgets.installers[name];
386			},
387			
388			installNow: function(WidgetConstructor, classname, tagname, rootelement) {
389				if (typeof rootelement === 'undefined' && window.opera) {
390					rootelement = document.body;
391				}
392				var elts = ccms.dom.getElementsByClassName(classname, tagname, rootelement);
393				for (var i = 0; i < elts.length; ++i) {
394					var v = new WidgetConstructor(elts[i]);
395					if (!WidgetConstructor.anonymouswidget) {
396						ccms.widgets.add(v, elts[i].id);
397					}
398				}
399		    },
400		    
401			install: function(WidgetConstructor, classname, tagname, rootelement) {
402				ccms.log.debug('Replace Me...  ccms.widgets.install: ' + classname + ', ' + tagname + ', ' + rootelement);
403				ccms.log.debug(WidgetConstructor);
404				if (typeof rootelement === 'undefined') {
405					if (window.opera) {
406						rootelement = document.body;
407					}
408					else {
409						rootelement = document;
410					}
411				}
412				if (typeof tagname === 'undefined') {tagname = '*';}
413				ccms.event.onDOMReady(function() {
414   					var elts = ccms.dom.getElementsByClassName(classname, tagname, rootelement);
415   					for (var i = 0; i < elts.length; ++i) {
416						var id = elts[i].id;
417						if (id === '') {id = ccms.dom.generateId(); elts[i].setAttribute('id', id);}
418   						ccms.widgets.add(new WidgetConstructor(elts[i]), id);
419   					}
420				});
421			}
422		},
423		
424		repr: function() {
425			var i;
426			var out = '';
427			if (arguments.length === 1) {
428				var a = arguments[0];
429				out += a + "\r\n";
430				if (typeof a === 'object') {
431					for (i in a) {
432						if (ccms.hasOwnProperty(a, i)) {
433							out += i + ": " + a[i] + "\r\n";
434						}
435					}
436				}
437			}
438			else {
439				for (i in arguments) {
440					if (ccms.hasOwnProperty(arguments, i)) {
441						out += ccms.repr(arguments[i]);
442					}
443				}
444			}
445			return out;
446		}
447		
448	};
449})());
450
451ccms.extend(ccms.config, {
452	get: function(name, default_value) {
453		return (typeof ccms.config[name] === 'undefined') ? default_value : ccms.config[name];
454	},
455	set: function(name, value) {
456		if (name !== 'set' && name !== 'get') {
457			return ccms.config[name] = value;
458		}
459	}
460});
461
462if (typeof jQuery !== 'undefined') {
463
464	(function($) {
465
466		$.cf = $.cf || {};
467
468		if (typeof $.cf.installer === 'undefined') {
469			var installers = [];
470
471			$.cf.installer = function(/*(func | selector, func)*/) {
472				if (arguments.length === 1) {
473					installers.push(arguments[0]);
474				}
475				else {
476					var sel = arguments[0], func = arguments[1];
477					installers.push(function($root) {
478						var $el = $root.find(sel);
479						if ($el.size()) {
480							return func($el);
481						}
482					});
483				}
484			};
485
486			$.fn.cf_install = function() {
487				this.each(function() {
488					var $this = $(this);
489					$.each(installers, function(i, func) {
490						func($this);
491					});
492				});
493			};
494		}
495
496		$(document).ready(function() {
497			setTimeout(function() {
498				if (typeof $.cf.installer.version === 'undefined') {
499					$('body').cf_install();
500				}
501			}, 1);
502		});
503
504	})(jQuery);
505
506}
507
508
509/*
510	create an html module.
511	all options are optional :)
512	{
513		'className': 'element',                    // additional classes to give module
514		'header': '<h3>title</h3>',                // html string or false to skip creating header
515		'body': '<p>something interesting</p>',    // html string or false to skip creating body
516		'footer': '<p>footer stuff</p>',           // html string or false to skip creating footer
517	}
518*/
519ccms.html.Module = function(options) {
520	if (!ccms.html.isAvailable) ccms.html.use();
521	
522	if (typeof options === 'undefined') options = {};
523	
524	if (typeof options.className === 'undefined') {options.className = 'module';}
525	else {options.className = 'module ' + options.className;}
526	
527	if (typeof options.id === 'undefined') {options.id = ccms.dom.generateId();}
528	
529	var module = ccms.html.DIV({'class':options.className, 'id':options.id});
530	
531	if (options.header !== false) {
532		if (typeof options.css_hd === 'undefined') {options.css_hd = 'header';}
533		var head = ccms.html.DIV({'class':options.css_hd});
534		head = module.appendChild(head);
535		if (typeof options.header === 'string') {head.innerHTML = options.header;}
536		else if (typeof options.header === 'object') {head.appendChild(options.header);}
537	}
538	if (options.body !== false) {
539		if (typeof options.css_bd === 'undefined') {options.css_bd = 'body';}
540		var body = ccms.html.DIV({'class':options.css_bd});
541		body = module.appendChild(body);
542		if (typeof options.body === 'string') {body.innerHTML = options.body;}
543		else if (typeof options.body === 'object') {body.appendChild(options.body);}
544	}
545	if (options.footer !== false) {
546		if (typeof options.css_ft === 'undefined') {options.css_ft = 'footer';}
547		var foot = ccms.html.DIV({'class':options.css_ft});
548		foot = module.appendChild(foot);
549		if (typeof options.footer === 'string') {foot.innerHTML = options.footer;}
550		else if (typeof options.footer === 'object') {foot.appendChild(options.footer);}
551	}
552	
553	return module;
554};
555
556ccms.html.MessageBox = function(options) {
557	if (typeof YAHOO === 'object' && typeof YAHOO.widget === 'object' && typeof YAHOO.widget.SimpleDialog === 'function') {
558		var p = ccms.update({
559			width: "300px",
560			fixedcenter: true,
561			visible: false,
562			draggable: true,
563			close: options.close,
564			text: options.body,
565			icon: options.icon,
566			constraintoviewport: true,
567			buttons: []
568		}, options);
569		p.buttons = [];
570		for (var k in options.buttons) {
571			if (ccms.hasOwnProperty(options.buttons, k)) {
572				var button = options.buttons[k];
573				var callback = null;
574				var isDefault = false;
575				if (button !== null) {
576					if (typeof button === 'object') {
577						if (ccms.hasOwnProperty(button, 'label')) {
578							k = button.label;
579						}
580						if (ccms.hasOwnProperty(button, 'onclick')) {
581							callback = button.onclick;
582						}
583						if (ccms.hasOwnProperty(button, 'isDefault')) {
584							isDefault = button.isDefault;
585						}
586					}
587					else if (typeof button === 'function') {
588						callback = button;
589					}
590				}
591				if (callback === null) {
592					callback = function() {this.hide();};
593				}
594				p.buttons.push({
595					text:k,
596					handler:callback,
597					isDefault:isDefault
598				});
599			}
600		}
601		var id = options.id || "MessageBox";
602		var dlg = new YAHOO.widget.SimpleDialog(id, p);
603		if (options.header) dlg.setHeader(options.header);
604		if (options['class']) ccms.dom.addClass(dlg.element, options['class']);
605		dlg.render('content');
606		return dlg;
607	}
608	else {
609		
610		ccms.html.MessageBox.close = function(e) {
611			this.parentNode.removeChild(this);
612		};
613		ccms.html.MessageBox.show = function() {
614			var parent = document.body;
615			if (typeof this.options.parent !== 'undefined') {
616				parent = $(this.options.parent);
617			}
618			parent.appendChild(this);
619			if (typeof this.options.center === 'string') {
620				var w = ccms.dom.getViewportWidth();
621				var h = ccms.dom.getViewportHeight();
622				var box = this;
623				if (this.options.backing) {
624					ccms.dom.setStyleObject(this, {
625						position:'absolute',
626						top:0, right:0, bottom:0, left:0
627					});
628					box = box.firstChild;
629				}
630				if (this.options.center.indexOf('x') > -1) {
631					ccms.dom.setX(box, (w - box.offsetWidth) / 2);
632				}
633				if (this.options.center.indexOf('y') > -1) {
634					ccms.dom.setY(box, window.scrollY + ((h - box.offsetHeight) / 2) - 64);
635				}
636				if (this.options.shadow) {
637					ccms.dom.setStyle(box, 'height', '' + box.firstChild.offsetHeight + 'px');
638				}
639			}
640		};
641		
642		if (!ccms.html.isAvailable) {ccms.html.use();}
643
644		if (typeof options === 'undefined') {options = {};}
645
646		if (typeof options.className === 'undefined') {options.className = 'ccmsMessageBox';}
647		if (typeof options.buttons === 'undefined') {
648			options.buttons = {
649				'Ok': null
650			};
651		}
652		
653		var callback;
654		var buttons = [];
655		var ul = ccms.html.UL({'class':'buttons'}), li;
656		for (var k in options.buttons) {
657			if (ccms.hasOwnProperty(options.buttons, k)) {
658				var klass = 'button';
659				var button = options.buttons[k];
660				callback = null;
661				if (button !== null) {
662					if (typeof button === 'object') {
663						if (ccms.hasOwnProperty(button, 'class')) {
664							klass += ' ' + button['class'];
665						}
666						if (ccms.hasOwnProperty(button, 'onclick')) {
667							callback = button.onclick;
668						}
669					}
670					else if (typeof button === 'function')
671						callback = button;
672				}
673				li = ccms.html.LI({'class':klass}, ccms.html.SPAN(k));
674				ul.appendChild(li);
675				buttons.push([li, callback]);
676			}
677		}
678
679		options.footer = ccms.html.DIV(ul, ccms.html.DIV({'class':'clear'}));
680		var module = ccms.html.Module(options);
681		if (options.shadow) {
682			module = ccms.html.DIV({'class':'ccmsMessageBoxShadow'}, module);
683		}
684		if (options.backing) {
685			module = ccms.html.DIV({'class':'ccmsMessageBoxBacking'}, module);
686		}
687		if (options['class']) ccms.dom.addClass(module, options['class']);
688		var close = ccms.html.MessageBox.close.bind(module);
689		for (var i = 0; i < buttons.length; ++i) {
690			li = buttons[i][0];
691			callback = buttons[i][1];
692			if (callback === null) {callback = close;}
693			else if (typeof callback === 'function') {callback = callback.chain(close);}
694			ccms.event.attach(li, 'click', callback);
695		}
696		module.show = ccms.html.MessageBox.show.bind(module);
697		module.options = options;
698		return module;
699		
700	}
701};
702
703
704
705ccms.DomBuilder = {
706    IE_TRANSLATIONS : {
707        'class' : 'className',
708        'for' : 'htmlFor'
709    },
710    ieAttrSet : function(a, i, el) {
711        var trans;
712        if ((trans = this.IE_TRANSLATIONS[i])) el[trans] = a[i];
713        else if (i === 'style') el.style.cssText = a[i];
714        else if (i.match(/^on/)) el[i] = new Function(a[i]);
715        else el.setAttribute(i, a[i]);
716    },
717    apply : function(o) { 
718        o = o || {};
719        var els = ("p|div|span|strong|em|img|table|tr|td|th|thead|tbody|tfoot|pre|code|" + 
720                    "h1|h2|h3|h4|h5|h6|ul|ol|li|form|input|textarea|legend|fieldset|" + 
721                    "select|option|blockquote|cite|br|hr|dd|dl|dt|address|a|button|abbr|acronym|" +
722                    "script|link|style|bdo|ins|del|object|param|
722col|colgroup|optgroup|caption|" + 
723                    "label|dfn|kbd|samp|var").split("|");
724        var el, i=0;
725        while ((el = els[i++])) {
726            o[el.toUpperCase()] = ccms.DomBuilder.tagFunc(el);
727        }
728        return o;
729    },
730    tagFunc : function(tag) {
731        return function() {
732            var a = arguments, at, ch; a.slice = [].slice; if (a.length>0) { 
733            if (a[0].nodeName || typeof a[0] === "string") ch = a; 
734            else { at = a[0]; ch = a.slice(1); } }
735            return ccms.DomBuilder.elem(tag, at, ch);
736        };
737    },
738    elem : function(e, a, c) {
739		a = a || {}; c = c || [];
740		var i, el = document.createElement(e), isIE = navigator.userAgent.match(/MSIE/);
741		for (i in a) {
742            if (typeof a[i] !== 'function') {
743    		    if (isIE) this.ieAttrSet(a, i, el);
744    		    else el.setAttribute(i, a[i]);
745            }
746	    }
747		for (i=0; i<c.length; i++) {
748			if (typeof c[i] === 'string') c[i] = document.createTextNode(c[i]);
749			el.appendChild(c[i]);
750		} 
751		return el;
752	}
753};
754
755ccms.extend(ccms.log, (function() {
756	var responders = {};
757	return {
758		debugging: false,
759		
760        levels: {
761			FATAL: 50,
762	        ERROR: 40,
763	        WARNING: 30,
764	        INFO: 20,
765	        DEBUG: 10
766		},
767		
768		output: function() {
769			var args = ccms.arrayOf(arguments);
770			var level = ccms.shift(args);
771			if (typeof(responders[level]) === 'function') {
772				responders[level].apply(this, args);
773			}
774		},
775		setup: function() {
776			for(var id in this.levels) {
777				var level = this.levels[id];
778				responders[level] = this._debug;
779				this[id.toLowerCase()] = this.output.partial(level);
780			}
781		},
782		addListener: function(level, responder) {
783			responders[level] = responder;
784		},
785		_debug: function() {
786			if (this.debugging) {
787				var body = document.getElementsByTagName('body');
788				if (body.length) {
789					body = body[0];
790				}
791				else {
792					if (typeof console !== 'undefined' && console.debug) {console.debug('%o', arguments);}
793					else if (typeof opera !== 'undefined' && opera.postError) {opera.postError(ccms.repr(arguments));}
794					else {alert(ccms.repr(arguments));}
795					return;
796				}
797				if (!this._debug.output) {
798					this._debug.output = document.createElement('pre');
799					this._debug.output.className = 'debugoutput';
800					body.appendChild(this._debug.output);
801				}
802				this._debug.output.innerHTML += this.stringify.apply(this, arguments);
803			}
804		},
805		stringify: function() {
806			var s = '';
807			for (var i = 0; i < arguments.length; ++i) {
808				if (typeof arguments[i] === 'object') {
809					s += ccms.repr(arguments[i]) + "\r\n";
810				}
811				else {
812					s += arguments[i] + "\n";
813				}
814			}
815			return s;
816		}
817	};
818})());
819
820// convert a value to an integer, also returning zero if NaN (like PHP does). This is useful for more
821// than just strings, so it's not a method on String prototype.
822function intval(value) {
823	value = parseInt(value, 10);
824	if (isNaN(value)) {
825		value = 0;
826	}
827	return value;
828}
829
830// convert a value to a float, also returning zero if NaN (like PHP does). This is useful for more
831// than just strings, so it's not a method on String prototype.
832function floatval(value) {
833	value = parseFloat(value);
834	if (isNaN(value)) {
835		value = 0.0;
836	}
837	return value;
838}
839
840// Sugar!
841Function.prototype.method = function(name,fn) {
842	if (typeof this.prototype[name] == 'undefined') {
843		this.prototype[name] = fn;
844	}
845	return this;
846};
847
848// callback fn can take these arguments, all optional: (propertyName, propertyValue)
849ccms.forEachProperty = function(thisObj, fn) {
850	for (var i in thisObj) {
851		if (ccms.hasOwnProperty(thisObj, i)) {
852			fn.call(thisObj, i, thisObj[i]);
853		}
854	}
855};
856
857Array.method('forEach', function(fn, thisObj) {
858	var scope = thisObj || window;
859	for (var i = 0, j = this.length; i < j; ++i) {
860		fn.call(scope, this[i], i, this);
861	}
862})
863.method('every', function(fn, thisObj) {
864	var scope = thisObj || window;
865	for (var i = 0, j = this.length; i < j; ++i) {
866		if (!fn.call(scope, this[i], i, this)) {
867			return false;
868		}
869	}
870	return true;
871})
872.method('some', function(fn, thisObj) {
873	var scope = thisObj || window;
874	for (var i = 0, j = this.length; i < j; ++i) {
875		if (fn.call(scope, this[i], i, this)) {
876			return true;
877		}
878	}
879	return false;
880})
881.method('map', function(fn, thisObj) {
882	var scope = thisObj || window;
883	var a = [];
884	for (var i = 0, j = this.length; i < j; ++i) {
885		a.push(fn.call(scope, this[i], i, this));
886	}
887	return a;
888})
889.method('filter', function(fn, thisObj) {
890	var scope = thisObj || window;
891	var a = [];
892	for (var i = 0, j = this.length; i < j; ++i) {
893		if (!fn.call(scope, this[i], i, this)) {
894			continue;
895		}
896		a.push(this[i]);
897	}
898	return a;
899})
900.method('indexOf', function(el, start) {
901	start = start || 0;
902	for (var i = start, j = this.length; i < j; ++i) {
903		if (this[i] === el) {
904			return i;
905		}
906	}
907	return -1;
908})
909.method('lastIndexOf', function(el, start) {
910	start = start || this.length;
911	if (start >= this.length) {
912		start = this.length;
913	}
914	if (start < 0) {
915		start = this.length + start;
916	}
917	for (var i = start; i >= 0; --i) {
918		if (this[i] === el) {
919			return i;
920		}
921	}
922	return -1;
923});
924
925Array.prototype.foreach = Array.prototype.forEach;
926
927if (!Array.prototype.reduce) {
928	Array.method('reduce', function(fn, initial) {
929		var i = 0, r = initial;
930		if (typeof initial === 'undefined') r = this[i++];
931		while (i < this.length) {
932			r = fn(r, this[i++]);
933		}
934		return r;
935	});
936}
937
938// like indexOf but uses a callback test instead of equality test
939if (!Array.prototype.findBy) {
940	Array.method('findBy', function(fn, start) {
941		start = start || 0;
942		for (var i = start, j = this.length; i < j; ++i) {
943			if (fn(this[i])) {
944				return i;
945			}
946		}
947		return -1;
948	});
949}
950
951if (!Array.prototype.unique) {
952	Array.method('unique', function() {
953		var a = [];
954		var l = this.length;
955		for (var i = 0; i < l; ++i) {
956			for (var j = i + 1; j < l; ++j) {
957			// If this[i] is found later in the array
958			if (this[i] === this[j])
959				j = ++i;
960			}
961			a.push(this[i]);
962		}
963		return a;
964	});
965}
966
967/*
968 * We add some useful methods to the String object
969 */
970
971String.prototype.startswith = function(text) {
972	return this.substring(0, text.length) === text;
973};
974String.prototype.endswith = function(text) {
975	return this.substring(this.length - text.length) === text;
976};
977String.prototype.trim = function(chars) {
978	if (typeof chars === 'undefined')
979		chars = '\\s';
980	return this.ltrim(chars).rtrim(chars);
981};
982String.prototype.ltrim = function(chars) {
983	if (typeof chars === 'undefined')
984		chars = '\\s';
985	var rx = new RegExp('^[' + chars + ']*(.*?)$', 'm');
986	return this.replace(rx, '$1');
987};
988String.prototype.rtrim = function(chars) {
989	if (typeof chars === 'undefined')
990		chars = '\\s';
991	var rx = new RegExp('^(.*?)[' + chars + ']*$', 'm');
992	return this.replace(rx, '$1');
993};
994
995String.prototype.stripTags = function() {
996	return this.replace(/<\/?[^>]+>/gi, '');
997};
998
999String.prototype.escapeHTML = function() {
1000	var div = document.createElement('div');
1001	var text = document.createTextNode(this);
1002	div.appendChild(text);
1003	return div.innerHTML;
1004};
1005
1006String.prototype.unescapeHTML = function() {
1007	var div = document.createElement('div');
1008	div.innerHTML = this.stripTags();
1009	return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
1010};
1011
1012String.prototype.parseHTML = function() {
1013	var div = document.createElement('div');
1014	div.innerHTML = this.trim();
1015	return div.firstChild;
1016};
1017
1018String.prototype.parseJSON = function () {
1019	if (JSON) return JSON.parse(this.toString());
1020	return eval('(' + this + ')');
1021};
1022
1023// Function.prototype.bind = function() {
1024// 	var __method = this;
1025// 	var args = ccms.arrayOf(arguments);
1026// 	var object = ccms.shift(args);
1027// 	return function() {
1028// 		return __method.apply(object, args.concat(ccms.arrayOf(arguments)));
1029// 	};
1030// };
1031Function.prototype.partial = function() {
1032	var __method = this;
1033	var args = ccms.arrayOf(arguments);
1034	return function() {
1035		return __method.apply(this, args.concat(ccms.arrayOf(arguments)));
1036	};
1037};
1038Function.prototype.rpartial = function() {
1039	var __method = this;
1040	var args = ccms.arrayOf(arguments);
1041	return function() {
1042		return __method.apply(this, ccms.arrayOf(arguments).concat(args));
1043	};
1044};
1045Function.prototype.chain = function() {
1046	var __method = this;
1047	var funcs = ccms.arrayOf(arguments);
1048	funcs.unshift(__method);
1049	return function() {
1050		var rv;
1051		var args = ccms.arrayOf(arguments);
1052		for (var i = 0; i < funcs.length; ++i) {
1053			rv = funcs[i].apply(this, args);
1054			if (false === rv) return false;
1055		}
1056		return rv;
1057	};
1058};
1059
1060// from: http://beppu.lbox.org/articles/2006/09/06/actsasaspect
1061function actsAsAspect(object) {
1062	object.yield = null;
1063	object.rv = {};
1064	object.before = function(method, f) {
1065		var original = eval("this." + method);
1066		this[method] = function() {
1067			f.apply(this, arguments);
1068			return original.apply(this, arguments);
1069		};
1070	};
1071	object.after = function(method, f) {
1072		var original = eval("this." + method);
1073		this[method] = function() {
1074			this.rv[method] = original.apply(this, arguments);
1075			return f.apply(this, arguments);
1076		};
1077	};
1078	object.around  = function(method, f) {
1079		var original = eval("this." + method);
1080		this[method] = function() {
1081			this.yield = original;
1082			return f.apply(this, arguments);
1083		};
1084	};
1085	return object;
1086}
1087
1088String.prototype.camelize = function() {
1089  var oStringList = this.split('-');
1090  if (oStringList.length === 1) return oStringList[0];
1091
1092  var camelizedString = this.indexOf('-') === 0
1093    ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
1094    : oStringList[0];
1095
1096  for (var i = 1, len = oStringList.length; i < len; i++) {
1097    var s = oStringList[i];
1098    camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
1099  }
1100
1101  return camelizedString;
1102};
1103
1104
1105ccms.URL = function(url) {
1106	this._fields = {'username' : 4, 'password' : 5, 'port' : 7, 'protocol' : 2, 'scheme': 2, 'host' : 6, 'path' : 8, 'url' : 0, 'query' : 9, 'fragment' : 10};
1107	this._regex = /^((\w+):\/\/)?((\w+):?(\w+)?@)?([^\/\?:]+):?(\d+)?(\/?[^\?#]+)?\??([^#]+)?#?(\w*)/;
1108	if (typeof url !== 'undefined')
1109		this.parse(url);
1110};
1111
1112ccms.URL.prototype.parse = function(url) {
1113	var r = this._regex.exec(url);
1114	if (!r) throw "ccms.URL::parse -> Invalid URL";
1115	for (var f in this._fields) {
1116		if (typeof r[this._fields[f]] === 'undefined') this[f] = '';
1117		else this[f] = r[this._fields[f]];
1118	}
1119	this.parseQuery(this.query);
1120};
1121ccms.URL.prototype.parseQuery = function(qs) {
1122	this.query = {};
1123	var params = qs.split('&');
1124	for (var i = 0; i < params.length; ++i) {
1125		if (params[i].length) {
1126			var kv = params[i].split("=");
1127			if (kv.length) this.query[kv[0]] = kv[1];
1128		}
1129	}
1130};
1131ccms.URL.prototype.appendPath = function(path) {
1132    this.path = this.path.rtrim('/') + '/' + path.ltrim('/');
1133    return this.path;
1134};
1135ccms.URL.prototype.prependPath = function(path) {
1136    this.path = '/' + path.trim('/') + '/' + this.path.ltrim('/');
1137    return this.path;
1138};
1139ccms.URL.prototype.pop = function() {
1140	this.path = this.path.replace(/\/[^\/]+\/?$/, '');
1141};
1142ccms.URL.prototype.localURL = function() {
1143	var s = '';
1144	if (this.path) s += this.path;
1145	if (ccms.keysOf(this.query).length > 0) s += '?' + urlencode(this.query);
1146	if (this.fragment !== '') s += '#' + this.fragment;
1147	return s;
1148};
1149ccms.URL.prototype.toString = function() {
1150	var s = '';
1151	if (this.protocol) s += this.protocol + '://';
1152	if (this.username || this.password) s += this.username + ':' + this.password + '@';
1153	if (this.host) s += this.host;
1154	if (this.port) s += ':' + this.port;
1155	return s + this.localURL();
1156};
1157
1158ccms.URL.open = function(url, new_window /*=false*/) {
1159	if (typeof new_window === 'undefined') new_window = false;
1160	if (typeof url === 'object') url = url.toString();
1161	if (!url.match(/^(\w+:\/\/|[\/\.])/)) url = 'http://' + url;
1162	if (new_window) return window.open(url);
1163	document.location.href = url;
1164	return true;
1165};
1166
1167ccms.URL.stripHost = function(url) {
1168	return url.replace(/^(\w+:\/\/[^\/]+)(.+)$/, '$2');
1169};
1170
1171// url encode all function arguments. if argument is an object, encode it's properties. e.g:
1172// urlencode({a:1, b:"this/thing"}, c, d, {e:3}) returns 'a=1&b=this%2Fthing&c&d&e=3'
1173function urlencode() {
1174	var output = [];
1175	for (var i = 0; i < arguments.length; ++i) {
1176		var arg = arguments[i];
1177		if (typeof arg === 'object') {
1178			for (var j in arg) {
1179				if (ccms.hasOwnProperty(arg, j)) {
1180					if (typeof arg[j] === 'object') {
1181						for (var k in arg[j]) {
1182							if (ccms.hasOwnProperty(arg[j], k)) {
1183								output[output.length] = encodeURIComponent(j) + '=' + encodeURIComponent(arg[j][k]);
1184							}
1185						}
1186					}
1187					else {
1188						output[output.length] = encodeURIComponent(j) + '=' + encodeURIComponent(arg[j]);
1189					}
1190				}
1191			}
1192		}
1193		else {
1194			output[output.length] = encodeURIComponent(arg);
1195		}
1196	}
1197	return output.join('&');
1198}
1199
1200// make a query string using the urlencode function
1201function ccmsQS(args) {
1202	return '?' + urlencode(args);
1203}
1204function ccmsQSAppend(url, args) {
1205	return url + (url.indexOf('?') > 0 ? '&' : '?') + urlencode(args);
1206}
1207
1208function ccmsFormData(formId, return_these_too) {
1209	var oForm = $(formId);
1210	if (!oForm) return false;
1211	var oElement, oName, oValue, oDisabled;
1212	var hasSubmit = false;
1213	var out, i, j;
1214	if (typeof return_these_too === 'undefined') out = {};
1215	else out = ccms.cloneOf(return_these_too);
1216	// Iterate over the form elements collection to construct the label-value pairs.
1217	for (i=0; i<oForm.elements.length; i++){
1218		oDisabled = oForm.elements[i].disabled;
1219		// If the name attribute is not populated, the form field's
1220		// value will not be submitted.
1221		if(oForm.elements[i].name !== ''){
1222			oElement = oForm.elements[i];
1223			oName = oForm.elements[i].name;
1224			oValue = oForm.elements[i].value;
1225		}
1226		// Do not submit fields that are disabled.
1227		if(!oDisabled && oElement)
1228		{
1229			switch (oElement.type)
1230			{
1231				case 'select-one':
1232					for(j=0; j<oElement.options.length; j++){
1233						if(oElement.options[j].selected){
1234							// out[oName] = oElement.options[j].value || oElement.options[j].text;
1235							out[oName] = oElement.options[j].value;
1236							break;
1237						}
1238					}
1239					break;
1240				case 'select-multiple':
1241					for(j=0; j<oElement.options.length; j++){
1242						if(oElement.options[j].selected){
1243							if (typeof out[oName] === 'undefined') out[oName] = [];
1244							// out[oName][out[oName].length] = oElement.options[j].value || oElement.options[j].text;
1245							out[oName][out[oName].length] = oElement.options[j].value;
1246						}
1247					}
1248					break;
1249				case 'radio':
1250				case 'checkbox':
1251					if(oElement.checked){
1252						out[oName] = oValue;
1253					}
1254					break;
1255				case 'file':
1256				//	this.sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
1257				// stub case as XMLHttpRequest will only send the file path as a string.
1258				case undefined:
1259				// stub case for fieldset element which returns undefined.
1260				case 'reset':
1261				// stub case for input type reset button.
1262				case 'button':
1263				// stub case for input type button elements.
1264					break;
1265				case 'submit':
1266					if(hasSubmit === false){
1267						hasSubmit = true;
1268						out[oName] = oValue;
1269					}
1270					break;
1271				default:
1272					if (oName.substring(oName.length - 2) === '[]') {
1273						if (typeof out[oName] === 'undefined') out[oName] = [];
1274						out[oName][out[oName].length] = oValue;
1275					}
1276					else
1277						out[oName] = oValue;
1278					break;
1279			}
1280		}
1281	}
1282	return out;
1283}
1284
1285ccms.async.when = function(condition, callback, timeout) {
1286	return new ccms.async.Poller(condition, callback, timeout);
1287};
1288
1289ccms.async.Poller = ccmsWaiter = function(condition, callback, timeout) {
1290	timeout   = timeout   || 500;
1291	var interval  = false;
1292
1293	function test() {
1294		if (condition()) {
1295			window.clearInterval(interval);
1296			interval = false;
1297			callback();
1298		}
1299	}
1300	
1301	self.start = function() {
1302		if (interval === false)
1303			interval = window.setInterval(test, timeout);
1304	};
1305	
1306	self.cancel = function() {
1307		if (interval !== false) {
1308			window.clearInterval(interval);
1309			interval = false;
1310		}
1311	};
1312	
1313	self.start();
1314};
1315
1316// Asynchronous stuff (ajax wrappers, timed events)
1317ccms.extend(ccms.async, {
1318	
1319	// create an XMLHttpRequest object
1320	getXMLHttpRequest: function () {
1321	    var self = arguments.callee;
1322	    if (!self.XMLHttpRequest) {
1323	        var tryThese = [
1324	            function () {return new XMLHttpRequest();},
1325	            function () {return new ActiveXObject('Msxml2.XMLHTTP.6.0');},
1326	            function () {return new ActiveXObject('Msxml2.XMLHTTP');},
1327	            function () {return new ActiveXObject('Microsoft.XMLHTTP');},
1328	            function () {return new ActiveXObject('Msxml2.XMLHTTP.4.0');},
1329	            function () {throw new Exception("Browser does not support XMLHttpRequest");}
1330	        ];
1331	        for (var i = 0; i < tryThese.length; i++) {
1332	            var func = tryThese[i];
1333	            try {
1334	                self.XMLHttpRequest = func;
1335	                return func();
1336	            } catch (e) {
1337	                // pass
1338	            }
1339	        }
1340	    }
1341	    return self.XMLHttpRequest();
1342	},
1343	
1344	// to use, set {..., HttpFactory:ccms.async.CachingXMLHttpRequest} in http() args
1345	CachingXMLHttpRequest: function() {
1346		return new ccms.async._CachingXMLHttpRequest();
1347	},
1348	
1349	// begin an async HTTP call. args should be a configuration object, e.g:
1350	// {method:'GET', url:'/fetch/this', onSuccess: successcallback, onFailure: failcallback, parameters:{userid:1234}}
1351	// method, onFailure, and parameters are optional, they default to GET, console.log, and {}.
1352	// call .cancel() on the return value to abort the request (doesn't work in all browsers).
1353	http: function(args) {
1354		var settings = ccms.extend({method:'GET', async:(args.onSuccess?true:false), onFailure:ccms.async.onHTTPError}, args);
1355		settings.cancelled = false;
1356		settings.cancel = function() {settings.cancelled = true;};
1357		settings.method = settings.method.toUpperCase();
1358		var http;
1359		if (typeof settings.HttpFactory === 'function') http = settings.HttpFactory();
1360		else http = this.getXMLHttpRequest();
1361		var postdata = null;
1362		
1363		// If there's a fragment, remove it
1364		var p;
1365		if ((p = settings.url.indexOf('#')) !== -1) {
1366			settings.url = settings.url.substring(0, p);
1367		}
1368
1369		if (settings.parameters) {
1370			if (settings.method === 'POST') {
1371				postdata = urlencode(settings.parameters);
1372			}
1373			else if (settings.method === 'GET' || settings.method === 'HEAD') {
1374		        settings.url += (settings.url.indexOf('?') > 0 ? '&' : '?') + urlencode(settings.parameters);
1375			}
1376		}
1377		if (settings.method === 'GET' && settings.url.length > 2048) {
1378			// ie max path length is 2048 characters. use post instead in that case with ccms workaround hack
1379			settings.method = 'POST';
1380			
1381			if (typeof settings.HttpFactory === 'function')
1382				// require normal http request for now, until CachingXMLHttpRequest supports POST
1383				http = this.getXMLHttpRequest();
1384			
1385			p = settings.url.indexOf('?');
1386			postdata = urlencode({'X-CCMS-TUNNELLED-GET':settings.url.substring(p + 1)});
1387			
1388			http.open(settings.method, settings.url.substring(0, p), settings.async);
1389		}
1390		else {
1391			http.open(settings.method, settings.url, settings.async);
1392		}
1393		if (postdata) {
1394			http.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
1395		}
1396		http.send(postdata);
1397		if (settings.async) {
1398			http.onreadystatechange = function() {
1399				if (settings.cancelled) {
1400					try {
1401						// unset this to fix a firefox memleak - inside try/catch cos i.e. throws type mismatch...
1402						http.onreadystatechange = null;
1403					} catch(e) {;}
1404					return;
1405				}
1406				if (http.readyState === 4){
1407					if (http.status === 200 || http.status === 304) {
1408						if (settings.onSuccess) {
1409							if (settings.parseJSON) settings.onSuccess.bind(settings)(http.responseText.parseJSON());
1410							else settings.onSuccess.bind(settings)(http);
1411						}
1412					}
1413					else {
1414						if (settings.onFailure) {
1415							if (settings.parseJSON) settings.onFailure.bind(settings)(http.responseText.parseJSON());
1416							else settings.onFailure.bind(settings)(http);
1417						}
1418					}
1419					try {
1420						http.onreadystatechange = null;
1421					} catch(e) {;}
1422				}
1423			};
1424		}
1425		else {
1426			return http.responseText;
1427		}
1428		return settings;
1429	},
1430
1431	submitForm: function(formid, args) {
1432		var oForm = $(formid);
1433		if (typeof args === 'undefined') args = {};
1434		if (typeof jQuery !== 'undefined' && jQuery.fn.ajaxSubmit && jQuery(oForm).find('input[type="file"]').size()) {
1435			var p = {
1436				data: args.parameters,
1437				success: function(resp, status) {
1438					if (status == 'success') args.onSuccess && args.onSuccess(resp);
1439					else args.onHTTPError && args.onHTTPError(resp);
1440				}
1441			};
1442			jQuery(oForm).ajaxSubmit(p);
1443		}
1444		else {
1445			if (typeof args.parameters === 'object')
1446				args.parameters = ccms.extend(args.parameters, ccmsFormData(oForm));
1447			else
1448				args.parameters = ccmsFormData(oForm);
1449			ccms.extend(args, {
1450				'url'        : oForm.action,
1451				'method'     : oForm.method
1452			});
1453			ccms.async.http(args);
1454		}
1455	},
1456
1457	onHTTPError: function(req) {
1458		ccms.log.debug('HTTP Error: ' + req.status + ' ' + req.statusText + "\n" + req.responseText);
1459	},
1460	
1461	after: function(timeout, callback) {
1462		return setTimeout(callback, timeout);
1463	},
1464	cancelTimeout: function(timeout_id) {
1465		return clearTimeout(timeout_id);
1466	},
1467	
1468	
1469	_cache: {},
1470	
1471	_CachingXMLHttpRequest: function() {
1472		var http = null, cache = null, asynchronous = false, key;
1473		var self = this;
1474		
1475		this.onreadystatechange = null;
1476		
1477		this.open = function(method, url, async) {
1478			asynchronous = async;
1479			key = null;
1480			if (method === 'GET') {
1481				key = method + url + async;
1482				if (typeof ccms.async._cache[key] === 'object') {
1483					cache = ccms.async._cache[key];
1484					if (typeof console === 'object' && typeof console.log === 'function') {
1485						if (typeof console.group === 'function') console.group("GET (ccms cached) " + url);
1486						console.log(cache);
1487						if (typeof console.groupEnd === 'function') console.groupEnd();
1488					}
1489					return;
1490				}
1491			}
1492			if (/*@cc_on!@*/false) {
1493				url = ccmsQSAppend(url, {'cachebust':(new Date()).getTime()});
1494			}
1495			http = ccms.async.getXMLHttpRequest();
1496			http.open(method, url, async);
1497		};
1498		
1499		this.send = function(data) {
1500			if (cache === null) {
1501				if (asynchronous) {
1502					http.onreadystatechange = _onreadystatechange.bind(this);
1503					http.send(data);
1504					return null;
1505				}
1506				else {
1507					cache = http.send(data);
1508					ccms.async._cache[key] = cache;
1509					return cache;
1510				}
1511			}
1512			else if (asynchronous) {
1513				ccms.async.after(1, _cached_onreadystatechange.bind(this));
1514				return null;
1515			}
1516			else {
1517				return cache;
1518			}
1519		};
1520		
1521		function _cached_onreadystatechange() {
1522			ccms.extend(self, cache);
1523			self.onreadystatechange(cache);
1524		}
1525		
1526		function _onreadystatechange() {
1527			self.readyState = http.readyState;
1528			if (http.readyState === 4 && http.status === 200) {
1529				self.status = http.status;
1530				try {
1531					http.onreadystatechange = null;
1532				}
1533				catch(e) {;}
1534				cache = {
1535					status: http.status,
1536					statusText: http.statusText,
1537					readyState: http.readyState,
1538					responseText: http.responseText
1539				};
1540				ccms.extend(self, cache);
1541				ccms.async._cache[key] = cache;
1542				self.onreadystatechange(cache);
1543			}
1544			else if (http.readyState === 4 && self.onreadystatechange !== null) {
1545				self.responseText = http.responseText;
1546				self.onreadystatechange(http);
1547			}
1548		}
1549	}
1550	
1551	
1552});
1553
1554ccms.async.jsr = (function() {
1555	var count = 0;
1556	var head = document.getElementsByTagName("head").item(0);
1557	return {
1558		callbacks: {},
1559		create_cb: function(onSuccess) {
1560			var c = count;
1561			this.callbacks[count] = function(json) {
1562				var s = $("ccmsjsr" + c);
1563				s.parentNode.removeChild(s); // can't remove from head here cos IE6 inserts the script tags into base tag!
1564				delete ccms.async.jsr.callbacks[c];
1565				return onSuccess(json);
1566			};
1567			return this.callbacks[count];
1568		},
1569		call: function(settings) {
1570			if (settings.parameters) {
1571		        settings.url += (settings.url.indexOf('?') > 0 ? '&' : '?') + urlencode(settings.parameters);
1572			}
1573			this.create_cb(settings.onSuccess);
1574		    settings.url += (settings.url.indexOf('?') > 0 ? '&' : '?') + urlencode({callback: 'ccms.async.jsr.callbacks[' + count + ']'});
1575			if (!settings.allow_cache) settings.url += '&noCacheIE=' + (new Date()).getTime();
1576			var scriptObj = document.createElement("script");
1577			scriptObj.setAttribute("type", "text/javascript");
1578			scriptObj.setAttribute("src", settings.url);
1579			scriptObj.setAttribute("id", "ccmsjsr" + count);
1580			head.appendChild(scriptObj);
1581			++count;
1582			if (typeof console !== 'undefined' && typeof console.log === 'function') console.log(settings.url);
1583		}
1584	};
1585})();
1586
1587ccms.async.processJSON = function(json) {
1588	ccms.ApiLinks.addMany(json.links);
1589	if (typeof json.js !== 'undefined') {
1590		json.js.foreach(ccms.require);
1591	}
1592};
1593
1594ccms.async.trapMultipleSubmits = function(root_element) {
1595	ccms.event.attach(root_element, 'click', function(e) {
1596		var target = ccms.event.getTarget(e);
1597		if (target.type === 'submit') {
1598			ccms.dom.getElementsBy(function(node) {
1599				return node.type === 'submit' && node.name !== target.name;
1600			}, 'input', root_element).foreach(function(node) {node.value = ''; node.name = '';});
1601		}
1602	});
1603};
1604
1605ccms.async.searchBox = (function() {
1606	return {
1607		config: {
1608			AJAX_KEYPRESS_DELAY: 0.5
1609		},
1610		
1611		isIgnoreKey: function(nKeyCode) {
1612		    if ((nKeyCode == 9) || (nKeyCode == 13)  || // tab, enter
1613		            (nKeyCode == 16) || (nKeyCode == 17) || // shift, ctl
1614		            (nKeyCode >= 18 && nKeyCode <= 20) || // alt,pause/break,caps lock
1615		            (nKeyCode == 27) || // esc
1616		            (nKeyCode >= 33 && nKeyCode <= 35) || // page up,page down,end
1617		            (nKeyCode >= 36 && nKeyCode <= 40) || // home,left,up, right, down
1618		            (nKeyCode >= 44 && nKeyCode <= 45)) { // print screen,insert
1619		        return true;
1620		    }
1621		    return false;
1622		},
1623		
1624		KeyMonitor: function(handler) {
1625			var _timer_id = -1;
1626			this.onKey = function(e) {
1627				alert(1);
1628				if (_timer_id != -1) {
1629					ccms.async.cancelTimeout(_timer_id);
1630					_timer_id = -1;
1631				}
1632				if (e.keyCode == 13 || !ccms.async.searchBox.isIgnoreKey(e.keyCode)) {
1633					_timer_id = ccms.async.after(ccms.async.searchBox.config.AJAX_KEYPRESS_DELAY * 1000, function() {
1634						_timer_id = -1;
1635						handler.startSearch();
1636					});
1637					if (e.keyCode == 13) return ccms.event.killEvent(e);
1638				}
1639			};
1640			//ccms.event.attach(handler.getInputField(), 'keydown', this.onKey);
1641		},
1642		
1643		SimpleHandler: function(text_input, api_settings) {
1644			this.getInputField = function() {return text_input;};
1645			this.startSearch = function() {
1646				if (text_input.value != '') {
1647					if (typeof api_settings.parameters != 'object') api_settings.parameters = {};
1648					api_settings.parameters.q = text_input.value;
1649					ccms.async.http(api_settings);
1650				}
1651			};
1652			this.mon = new ccms.async.searchBox.KeyMonitor(this);
1653		}
1654	};
1655})();
1656
1657
1658/*
1659 * Event manager - register events in a x-browser fashion, with workarounds for IE memory leaks.
1660 */
1661if (typeof YAHOO !== 'undefined' && typeof YAHOO.util !== 'undefined') {
1662	if (typeof YAHOO.util.Event !== 'undefined') {
1663		ccms.event = YAHOO.util.Event;
1664		ccms.event.CustomEvent = YAHOO.util.CustomEvent;
1665		ccms.event.addLoadEvent = function(handler, oScope, bOverride) {return YAHOO.util.Event.addListener(window, 'load', handler, oScope, bOverride);};
1666		ccms.event.attach = ccms.event.addListener;
1667		ccms.event.detach = ccms.event.removeListener;
1668		ccms.event.killEvent = function(e) {ccms.event.stopEvent(e); return false;};
1669		ccms.event.YAHOO_onDOMReady = ccms.event.onDOMReady;
1670		ccms.event.onDOMReady = function(callback, data, scope) {
1671			// wrap callback function cos onDOMReady eats exceptions
1672			return YAHOO.util.Event.YAHOO_onDOMReady(function() {
1673				try {
1674					callback.apply(this, arguments);
1675				}
1676				catch(ex) {
1677					if (typeof console === 'object' && typeof console.error === 'function') {
1678						if (typeof ex.stack !== 'undefined') {
1679							console.error(ex.message, ex.stack);
1680						}
1681						else {
1682							console.error(ex);
1683						}
1684					}
1685					else ccms.debug.error(ex);
1686					throw ex;
1687				}
1688			}, data, scope);
1689		};
1690	}
1691	else {
1692		document.write('<b>ccms.event unavailable, because the YAHOO Event library has not been included before ccms.js</b>');
1693	}
1694	if (typeof YAHOO.util.Dom !== 'undefined') {
1695		ccms.dom = YAHOO.util.Dom;
1696	}
1697}
1698else {
1699	document.write('<b>ccms.dom and ccms.event unavailable, because the YAHOO libraries have not been included</b>');
1700}
1701
1702ccms.event.onDOMReady(function() {
1703	if (typeof jQuery !== 'undefined') jQuery.noConflict();
1704	ccms.dom.ready = true;
1705});
1706
1707
1708
1709/*
1710	global events system, allows decoupled notifications between different components.
1711	basic example:
1712	
1713	ccms.events.subscribe('video.play', function(ev_name, ev_args) {alert('Playing!');});
1714	
1715	in "video" component:
1716	ccms.events.add('video.play');
1717	when play pressed:
1718	ccms.events.fire('video.play');
1719*/
1720ccms.events = (function() {
1721	var events = {};
1722	var subs = {};
1723	
1724	return {
1725		subscribe: function(p_type, op_fn, p_obj, p_override) {
1726			var p_fn = function() {
1727				try {
1728					return op_fn.apply(this, arguments);
1729				}
1730				catch(e) {
1731					console.log(e);
1732				}
1733				return null;
1734			};
1735			var ce = events[p_type];
1736			if (ce) {
1737				ce.subscribe(p_fn, p_obj, p_override);
1738			}
1739			else {
1740				if (!subs[p_type]) {
1741					subs[p_type] = [];
1742				}
1743				subs[p_type].push({
1744					fn: p_fn,
1745					obj: p_obj,
1746					override: p_override
1747				});
1748			}
1749		},
1750		unsubscribe: function(p_type, p_fn, p_obj) {
1751			var ce = events[p_type];
1752			if (ce) {
1753				return ce.unsubscribe(p_fn, p_obj);
1754			}
1755			else {
1756				return false;
1757			}
1758		},
1759		add: function(p_type, p_config) {
1760			var opts = p_config || {};
1761		
1762			if (events[p_type]) {
1763				;
1764			}
1765			else {
1766				var scope  = opts.scope  || this;
1767				var silent = opts.silent || null;
1768				var ce = new ccms.event.CustomEvent(p_type, scope, silent);
1769				events[p_type] = ce;
1770				if (opts.onSubscribeCallback) {
1771					ce.subscribeEvent.subscribe(opts.onSubscribeCallback);
1772				}
1773				var qs = subs[p_type];
1774				if (qs) {
1775					for (var i=0; i<qs.length; ++i) {
1776						ce.subscribe(qs[i].fn, qs[i].obj, qs[i].override);
1777					}
1778				}
1779			}
1780
1781			return events[p_type];
1782		},
1783		fire: function(p_type, arg1, arg2, etc) {
1784			var ce = events[p_type];
1785			if (ce) {
1786				var args = [];
1787				for (var i=1; i<arguments.length; ++i) {
1788					args.push(arguments[i]);
1789				}
1790				return ce.fire.apply(ce, args);
1791			}
1792			else {
1793				return null;
1794			}
1795		}
1796	};
1797})();
1798
1799
1800// The MAGIC $ function :)
1801// usage:
1802// $('foo') returns the node with id='foo'
1803// $('foo', 'bar', 'oof') returns an array of the elements with specified ids
1804// if parameter(s) is (are) already objects they're just returned.
1805function $() {
1806	var elements = [];
1807	for (var i = 0; i < arguments.length; i++) {
1808		var element = arguments[i];
1809		if (typeof element === 'string')
1810			element = document.getElementById(element);
1811		if (arguments.length === 1)
1812			return element;
1813		elements[elements.length] = element;
1814	}
1815	return elements;
1816};
1817
1818/*
1819 * ccms DOM helpers:
1820 */
1821
1822if (!window.Node || !window.Node.ELEMENT_NODE) {
1823	var Node = {
1824		ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5,
1825		ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10,
1826		DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12
1827	};
1828}
1829
1830ccms.extend(ccms.dom, {
1831	// toggle a nodes visibility
1832	toggle: function(e, style) {
1833		if (typeof e === 'string')
1834			e = $(e);
1835		if (e.style.display !== 'none' ) {
1836			e.style.display = 'none';
1837		}
1838		else if (style) e.style.display = style;
1839		else {
1840			e.style.display = '';
1841		}
1842	},
1843	isHidden: function(e) {
1844		if (typeof e === 'string') e = $(e);
1845		return (e.style.display === 'none');
1846	},
1847	// hide a node
1848	hide: function(e) {
1849		if (typeof e === 'string')
1850			e = $(e);
1851		e.style.display = 'none';
1852	},
1853	// show a node
1854	show: function(e, style) {
1855		if (typeof e === 'string')
1856			e = $(e);
1857		if (style) e.style.display = style;
1858		else e.style.display = '';
1859	},
1860	refresh: function(e) {
1861		if (typeof e === 'undefined')
1862			e = document.body;
1863		else if (typeof e === 'string')
1864			e = $(e);
1865		
1866		ccms.dom.hide(e);
1867		ccms.dom.show(e);
1868	},
1869	// check a node is visible by checking visbility / display of self and ancestors
1870	isVisible: function(el, root) {
1871		if (typeof root == 'undefined') root = document.body;
1872		while (el && el !== root) {
1873			if (ccms.dom.getStyle(el, 'display') == 'none' || ccms.dom.getStyle(el, 'visibility') == 'hidden') {
1874				return false;
1875			}
1876			el = el.parentNode;
1877		}
1878		return true;
1879	},
1880	// swap two nodes
1881	swapNode: function(n1, n2) {
1882		if (n1.swapNode) { // ie has native swapNode support
1883			n1.swapNode(n2);
1884		}
1885		else {
1886			var p = n2.parentNode;
1887			var s = n2.nextSibling;
1888
1889			if (s == n1) {
1890				p.insertBefore(n1, n2);
1891			}
1892			else if (n2 == n1.nextSibling) {
1893				p.insertBefore(n2, n1);
1894			}
1895			else {
1896				n1.parentNode.replaceChild(n2, n1);
1897				p.insertBefore(n1, s);
1898			}
1899		}
1900	},
1901	// insert a node after another
1902	insertAfter: function(nInsert, nPrevious) {
1903		var nParent = nPrevious.parentNode;
1904		if (nPrevious.nextSibling) {
1905			nInsert = nParent.insertBefore(nInsert, nPrevious.nextSibling);
1906		}
1907		else {
1908			nInsert = nParent.appendChild(nInsert);
1909		}
1910		return nInsert;
1911	},
1912	// get an element's ancestor by tag and/or class name
1913	getParentByClassName: function(oElm, strTagName, strClassName) {
1914		var tf = ccms.dom.hasTagName.rpartial(strTagName.toLowerCase());
1915		var f;
1916		if (typeof strClassName === 'string') {
1917			var cf = ccms.dom.hasClass.rpartial(strClassName);
1918			f = function(n) {return tf(n) && cf(n);};
1919		}
1920		else {
1921			f = function(n) {return tf(n);};
1922		}
1923		return ccms.dom.getAncestor(oElm, f);
1924	},
1925	
1926	getSelfOrAncestorBy: function(callback, node) {
1927		while(node) {
1928			if (node.nodeType === Node.ELEMENT_NODE) {
1929				if (callback(node))
1930					break;
1931			}
1932			node = node.parentNode;
1933		}
1934		return node;
1935	},
1936	
1937	getElementsByClassNameRE: function(regex, strTagName, oElm) {
1938		if (typeof(regex) == 'string') regex = RegExp(regex);
1939		return ccms.dom.getElementsBy(function(node) {return node.className.match(regex);}, strTagName, oElm);
1940	},
1941	
1942	getElementByClassName: function(strClassName, strTagName, oElm) {
1943		if (window.opera) {
1944			if (typeof oElm === 'undefined') oElm = document;
1945			if (oElm.nodeType === Node.DOCUMENT_NODE) oElm = oElm.body;
1946		}
1947		return ccms.dom.getElementsByClassName(strClassName, strTagName, oElm)[0];
1948	},
1949	
1950	getLabelFor: function(oElm) {
1951		var oLabel = null;
1952		
1953		if (typeof oElm === 'string')
1954			oElm = $(oElm);
1955		
1956		if ((oLabel = ccms.dom.getParentByClassName(oElm, 'label')))
1957			return oLabel;
1958		else if (oElm.getAttribute('id'))
1959			return ccms.dom.getElementsBy(function(node) {
1960				return node.htmlFor == oElm.getAttribute('id');
1961			})[0];
1962		else
1963			return null;
1964	},
1965	
1966	getChildrenBy: function(callback, parent, elements_only/*=true*/) {
1967		if (typeof elements_only === 'undefined') elements_only = true;
1968		var kids = [];
1969		var n = parent.firstChild;
1970		while(n) {
1971			if ((!elements_only || ccms.dom.isElementNode(n)) && callback(n))
1972				kids.push(n);
1973			n = n.nextSibling;
1974		}
1975		return kids;
1976	},
1977	
1978	getChildrenByTagName: function(tagName, parent) {
1979		return ccms.dom.getChildrenBy(ccms.dom.hasTagName.rpartial(tagName), parent);
1980	},
1981	
1982	getChildrenByClassName: function(className, tagName, parent) {
1983		var cf = ccms.dom.hasClass.rpartial(className);
1984		var f;
1985		if (typeof tagName === 'string') {
1986			var tf = ccms.dom.hasTagName.rpartial(strTagName.toLowerCase());
1987			f = function(n) {return tf(n) && cf(n);};
1988		}
1989		else {
1990			f = function(n) {return cf(n);};
1991		}
1992		return ccms.dom.getChildrenBy(f, parent);
1993	},
1994	
1995	getElementPosition: function(element) {
1996		if (element.offsetParent) {
1997			for (var posX = 0, posY = 0; element.offsetParent; element = element.offsetParent) {
1998				posX += element.offsetLeft;
1999				posY += element.offsetTop;
2000			}
2001			return [posX, posY];
2002		}
2003		else {
2004			return [element.x, element.y];
2005		}
2006	},
2007	
2008	getDocumentScroll: function() {
2009		return [ccms.dom.getDocumentScrollLeft, ccms.dom.getDocumentScrollTop];
2010	},
2011	
2012	getWidth: function(o) {
2013		if (typeof o.innerWidth === 'number') {
2014			return o.innerWidth;
2015		}
2016		else if (o.clientWidth) {
2017			return o.clientWidth;
2018		}
2019		return 0;
2020	},
2021	getHeight: function(o) {
2022		if (typeof o.innerHeight === 'number') {
2023			return o.innerHeight;
2024		}
2025		else if (o.clientHeight) {
2026			return o.clientHeight;
2027		}
2028		return 0;
2029	},
2030	
2031	isSubnodeOf: function(parent, subnode) {
2032		if (subnode) {
2033			var n = subnode.parentNode;
2034			while (n) {
2035				if (n === parent) {
2036					return true;
2037				}
2038				n = n.parentNode;
2039			}
2040		}
2041		return false;
2042	},
2043
2044	hasMovedOutOf: function(eventobj, element) {
2045		var src = ccms.event.getTarget(eventobj);
2046		if (element !== src && src && !ccms.dom.isSubnodeOf(element, src)) {return true;}
2047		var rel = ccms.event.getRelatedTarget(eventobj);
2048		return rel !== element && !ccms.dom.isSubnodeOf(element, rel);
2049	},
2050	getStyleObject: function(element, style_names) {
2051		element = $(element);
2052		var styles;
2053		if (element) {
2054			styles = {};
2055			style_names.foreach(function(name) {styles[name] = ccms.dom.getStyle(element, name);});
2056		}
2057		return styles;
2058	},
2059	setStyleObject: function(element, styles) {
2060		element = $(element);
2061		if (element) {for (var name in styles) {ccms.dom.setStyle(element, name, styles[name]);}}
2062	},
2063	setStyleByClass: function(t,c,p,v, root) { // tag, class, property, value, optional root element
2064		ccms.dom.getElementsByClassName(c, t, root).foreach(function(node) {ccms.dom.setStyle(node, p, v);});
2065	},
2066	
2067	toggleClass: function(element, className) {
2068		if (ccms.dom.hasClass(element, className))
2069			ccms.dom.removeClass(element, className);
2070		else
2071			ccms.dom.addClass(element, className);
2072	},
2073	
2074	swapClass: function(element, removeClass, addClass) {
2075		if (ccms.dom.hasClass(element, removeClass))
2076			ccms.dom.removeClass(element, removeClass);
2077		ccms.dom.addClass(element, addClass);
2078	},
2079	
2080	getElementIndex: function(node, includeNonElementNodes) {
2081		var n = node.parentNode.firstChild;
2082		var i = 0;
2083		if (typeof includeNonElementNodes === 'undefined')
2084			includeNonElementNodes = false;
2085		while(n) {
2086			if (n === node) return i;
2087			if (includeNonElementNodes || n.nodeType === Node.ELEMENT_NODE)
2088				++i;
2089			n = n.nextSibling;
2090		}
2091		return -1;
2092	},
2093	
2094	removeChildren: function(el) {
2095		var prev;
2096		var node = el.lastChild;
2097		while(node) {
2098			prev = node.previousSibling;
2099			el.removeChild(node);
2100			node = prev;
2101		}
2102	},
2103	
2104	getNext: function(node, callback, oData) {
2105		var cb = callback;
2106		if (!cb) cb = ccms.dom.isElementNode;
2107		var n = node.nextSibling;
2108		while(n && !cb(n, oData)) {
2109			n = n.nextSibling;
2110		}
2111		return n;
2112	},
2113	getPrevious: function(node, callback, oData) {
2114		var cb = callback;
2115		if (!cb) cb = ccms.dom.isElementNode;
2116		var n = node.previousSibling;
2117		while(n && !cb(n, oData)) {
2118			n = n.previousSibling;
2119		}
2120		return n;
2121	},
2122	getAncestor: function(node, callback, oData) {
2123		var cb = callback;
2124		if (!cb) cb = ccms.dom.isElementNode;
2125		var n = node.parentNode;
2126		while(n && !cb(n, oData)) {
2127			n = n.parentNode;
2128		}
2129		return n;
2130	},
2131	getChild: function(node, callback, oData) {
2132		var cb = callback;
2133		if (!cb) cb = ccms.dom.isElementNode;
2134		var n = node.firstChild;
2135		while(n && !cb(n, oData)) {
2136			n = n.nextSibling;
2137		}
2138		return n;
2139	},
2140	
2141	isElementNode: function(node) {return node.nodeType === Node.ELEMENT_NODE;},
2142	//hasClass: function(node, sClassName) {return !sClassName || ccms.contains(node.className.split(' '), sClassName);},
2143	hasTagName: function(node, sTagName) {return sTagName === '*' || (typeof node.tagName !== 'undefined' && node.tagName.toUpperCase() === sTagName.toUpperCase());},
2144	
2145	hasRel: function(node, sRel) { return !sRel || (node.getAttribute('rel') && ccms.contains(node.getAttribute('rel').split(' '), sRel));},
2146	
2147	_waiting: 0,
2148	pushWaitingClass: function() {
2149		++ccms.dom._waiting;
2150		ccms.dom.addClass(document.body, 'waiting');
2151	},
2152	popWaitingClass: function() {
2153		if (--ccms.dom._waiting <= 0) {
2154			ccms.dom.removeClass(document.body, 'waiting');
2155		}
2156	},
2157	
2158	// replace id attributes in html string with a generated one if the id already exists
2159	fixDuplicateIDs: function(html) {
2160		var bits = html.match(/id=('.+?'|".+?")/g);
2161		bits.foreach(function(attr) {
2162			var id = attr.match(/('.+?'|".+?")/);
2163			id = id[1].substring(1, id[1].length - 1);
2164			if ($(id)) {
2165				var new_attr = 'id="' + id + '-' + ccms.dom.generateId() + '"';
2166				html = html.replace(attr, new_attr);
2167			}
2168		});
2169		return html;
2170	},
2171	
2172	// set option with specified value to selected
2173	setSelectedIndexByValue: function(select, value) {
2174		for(var i = 0; i < select.options.length; ++i) {
2175			if (value == select.options[i].value) {
2176				select.selectedIndex = i;
2177				break;
2178			}
2179		}
2180	},
2181	
2182	ready: false
2183});
2184
2185ccms.dom.updatePopupLinks = function(root) {
2186	ccms.dom.getElementsByClassName('external', 'a', document.body).foreach(ccms.dom.setExternalLink);
2187	ccms.dom.getElementsByClassName('external', 'form', document.body).foreach(ccms.dom.setExternalLink);
2188};
2189ccms.dom.updateRelExternalLinks = function(root) {
2190	var queryfunc = function(node) {return ccms.dom.hasRel(node, 'external');};
2191	ccms.dom.getElementsBy(queryfunc, 'a', document.body).forEach(ccms.dom.setExternalLink);
2192};
2193ccms.dom.updateExternalLinks = function(root, subdomains) {
2194	subdomains = subdomains || [];
2195	var re = subdomains.length ? new RegExp('^(' + subdomains.join('|') + ')\.') : '';
2196	var queryfunc = function(node) {
2197		return node.href.startswith('http') && (window.location.hostname.replace(re, '') != node.hostname.replace(re, '') || ccms.dom.hasRel(node, 'external'));
2198	};
2199	ccms.dom.getElementsBy(queryfunc, 'a', document.body).forEach(ccms.dom.setExternalLink);
2200};
2201ccms.dom.updateHumanoids = function (root) {
2202	var humanoids = document.getElementsByTagName('input');
2203	var d = new Date();
2204	for (var i = 0; i < humanoids.length; i++) {
2205		if (humanoids[i].name == 'humanoid') {
2206			humanoids[i].value = d.getTime();
2207		}
2208	}
2209}
2210
2211/* Override me if you want to do something different/more */
2212ccms.dom.setExternalLink = function(node) {
2213	node.setAttribute('target', '_blank');
2214}
2215
2216ccms.dom.updateHumanoids = function(root) {
2217	var d = new Date();
2218	var humanoids = document.getElementsByTagName('input');
2219	for (var i = 0; i < humanoids.length; i++) {
2220		if (humanoids[i].name == 'humanoid') {
2221			humanoids[i].value = d.getTime();
2222		}
2223	}
2224};
2225
2226ccms.extend(ccms.css, {
2227	styleSheets: [],
2228	require: function(url)
2229	{
2230		if (this.styleSheets[url]) return;
2231		this.styleSheets[url] = true;
2232		if (navigator.userAgent.indexOf('MSIE') > 0)
2233		{
2234			document.write('<link rel="stylesheet" type="text/css" href="' + url + '" />');
2235		}
2236		else
2237		{
2238			var s = document.createElement('link');
2239			s.setAttribute('rel', 'stylesheet');
2240			s.setAttribute('type', 'text/css');
2241			s.setAttribute('href', url);
2242			document.getElementsByTagName('head')[0].appendChild(s);
2243		}
2244	}
2245});
2246
2247ccms.namespace('ccms.screen');
2248ccms.extend(ccms.screen, (function() {
2249	var classes = [];
2250	var widths  = [];
2251	var current_class = '';
2252	
2253	return {
2254		setScreenClass: function() {
2255			var width = document.documentElement.clientWidth;
2256			var new_class = classes[widths[0]];
2257
2258			for (var i in widths) {
2259				var w = widths[i];
2260
2261				if (w <= width) new_class = classes[w];
2262			}
2263
2264			if (current_class !== new_class) {
2265				if (current_class !== '')
2266					ccms.dom.removeClass(document.body, current_class);
2267				ccms.dom.addClass(document.body, current_class = new_class);
2268
2269				ccms.require('/js/ccmsBrowserCapabilities.js');
2270				
2271				ccms.async.when(function() {return (typeof ccms.browser.getCapabilities === 'function');}, function() {
2272					ccms.async.http({
2273						url: '/browsercaps',
2274						method: 'POST',
2275						parameters: {'json': JSON.stringify(ccms.browser.getCapabilities())},
2276						onSuccess: function(req) {},
2277						onFailure: function(req) {ccms.log.debugging = true; ccms.log.debug('ccmsBrowserCapabilities: ' + req.status + ' ' + req.statusText + "\n" + req.responseText);}
2278					});
2279				});
2280			}
2281		},
2282		setupMonitor: function(dat, current) {
2283			var sorter = function sortNumber(a, b) { return a - b; };
2284
2285			if (current) current_class = current;
2286
2287			var i = 0;
2288			for (var w in dat) {
2289				widths[i++] = w;
2290				classes[w] = dat[w];
2291			}
2292			widths.sort(sorter);
2293
2294			if (widths.length > 0) {
2295				ccms.event.addLoadEvent(ccms.screen.setScreenClass);
2296				ccms.event.addListener(window, 'resize', ccms.screen.setScreenClass);
2297			}
2298		}
2299	};
2300})());
2301
2302ccms.cookie = {
2303	get: function(cookieName, default_value) {
2304		var cookieNameStart,valueStart,valueEnd,value;
2305		cookieNameStart = document.cookie.indexOf(cookieName+'=');
2306		if (cookieNameStart < 0) {
2307		    if (typeof default_value === 'undefined') return null;
2308		    return default_value;
2309		}
2310		valueStart = document.cookie.indexOf(cookieName+'=') + cookieName.length + 1;
2311		valueEnd = document.cookie.indexOf(";",valueStart);
2312		if (valueEnd === -1){valueEnd = document.cookie.length;}
2313		value = document.cookie.substring(valueStart,valueEnd );
2314		value = unescape(value);
2315		if (value === '') {
2316		    if (typeof default_value === 'undefined') return null;
2317		    return default_value;
2318		}
2319		return value;
2320	},
2321	set: function(cookieName,value,hoursToLive,path,domain,secure) {
2322		var expireString,timerObj,expireAt,pathString,domainString,secureString,setCookieString;
2323		/* If no hoursToLive argument, or it is not numeric, do not set expiration */
2324		if (!hoursToLive || typeof hoursToLive !== 'number' || parseInt(hoursToLive, 10) === 'NaN'){
2325			expireString = '';
2326		}
2327		else {
2328			timerObj = new Date();
2329			timerObj.setTime(timerObj.getTime()+(parseInt(hoursToLive, 10)*60*60*1000));
2330			expireAt = timerObj.toGMTString();
2331			expireString = ";expires="+expireAt;
2332		}
2333		/* If no path argument, or argument is empty string, set path to default of /  */
2334		pathString = ";path=";
2335		(!path || path === '') ? pathString += "/" : pathString += path;
2336		/* If no domain argument, or argument is empty string, set domain to default of window.location.hostname */
2337		domainString = "; domain=";
2338		(!domain || domain === '') ? domainString += window.location.hostname : domainString += domain;
2339		/* If secure argument is the BOOL true, set SSL string accordingly.  Otherwise, do not set it. */
2340		(secure === true) ? secureString = ";secure" : secureString = '';
2341		value = escape(value);
2342		setCookieString = cookieName+"="+(value)+expireString+pathString+domainString;
2343		document.cookie = setCookieString;
2344	},
2345	del: function(cookieName,path,domain){
2346          (!path || !path.length) ? path='' : path=path;
2347          (!domain || !domain.length) ? domain='' : domain=domain;
2348		ccms.cookie.set(cookieName,'',-8760,path,domain);
2349	},
2350	test: function(){
2351		ccms.cookie.set('cT','acc');
2352		var runTest = ccms.cookie.get('cT');
2353		if (runTest === 'acc'){
2354			ccms.cookies.del('cT');
2355			testStatus = true;
2356		}
2357		else {
2358			testStatus = false;
2359		}
2360		return testStatus;
2361	}
2362};
2363
2364/* Add a flash message from JavaScript */
2365ccms.flash = function(html)
2366{
2367	/* If there's a message, turn it into html add it to the document */
2368	if (typeof html !== 'undefined') {
2369		var block = html, content;
2370		if (html.constructor.prototype === String.prototype) /* Assume this is an HTML snippit */
2371		{
2372			if (html === '') {
2373				block = false;
2374			}
2375			else {
2376				/* A cheeky way of getting the HTML as a DOM object */
2377				block = document.createElement('div');
2378				block.innerHTML = html;
2379				block = block.childNodes[0];
2380			}
2381		}
2382		if (block) {
2383			if ((content = $('content'))) {
2384				if (content.childNodes.length > 0) {
2385					content.insertBefore(block, content.childNodes.item(0));
2386				}
2387				else {
2388					content.appendChild(block);
2389				}
2390			}
2391		}
2392	}
2393
2394	/* Find all of the flash divs, if there's more than one then consolidate them */
2395	var flashes = ccms.arrayOf(ccms.dom.getElementsByClassName('flash', 'div'));
2396	if (flashes.length > 0) {
2397		flash = flashes[0];
2398		if (flashes.length > 1) {
2399			for (var f = 1; f < flashes.length; ++f) {
2400				var kids = ccms.arrayOf(flashes[f].getElementsByTagName('p'));
2401				for (var k = 0; k < kids.length; ++k) {
2402					flash.appendChild(kids[k]);
2403				}
2404				flashes[f].parentNode.removeChild(flashes[f]);
2405			}
2406		}
2407		ccms.flash.attachFlash(flash);
2408	}
2409};
2410
2411ccms.flash.attachFlash = function(root_element) {
2412	/* Override me to setup animations */
2413};
2414
2415ccms.event.attach(window, 'load', function(e) {ccms.flash();});
2416
2417ccms.log.setup();
2418
2419ccms.event.addLoadEvent(ccms.detectScripts);
2420ccms.event.addLoadEvent(ccms.dom.updateHumanoids);
2421
2422ccms.widgets.addInstaller('updatePopupLinks', ccms.dom.updatePopupLinks);
2423ccms.widgets.addInstaller('updateHumanoids', ccms.dom.updateHumanoids);
2424
2425(function() {
2426	var f = document.createElement('input');
2427	// Run through HTML5's new input attributes to see if the UA understands any.
2428	// Mike Taylr has created a comprehensive resource for testing these attributes
2429	//   when applied to all input types: 
2430	//   http://miketaylr.com/code/input-type-attr.html
2431	// spec: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
2432	var input = (function(props) {
2433		var attrs = {};
2434		for ( var i in props ) {
2435			attrs[ props[i] ] = !!(props[i] in f);
2436		}
2437		return attrs;
2438	})('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' '));
2439
2440})();
2441
2442
2443ccms.ApiLinks = (function() {
2444	var links = [];
2445	var have_document = false;
2446	
2447	var _boundcall = function(config) {
2448		config.api = this;
2449		return ccms.ApiLinks.call(config);
2450	};
2451	
2452	ccms.event.onDOMReady(function() {ccms.ApiLinks.extract();});
2453	
2454	return {
2455		
2456		extract: function(root_element) {
2457			if (typeof root_element === 'undefined') {
2458				if (have_document) return true;
2459				have_document = true;
2460				root_element = document;
2461			}
2462			ccms.arrayOf(root_element.getElementsByTagName('link')).foreach(function(node) {
2463				links.push({
2464					'href':node.getAttribute('href'),
2465					'rel':node.getAttribute('rel'),
2466					'title':node.getAttribute('title'),
2467					'type':node.getAttribute('type'),
2468					'parameters': {},
2469					'call': _boundcall
2470				});
2471			});
2472			return true;
2473		},
2474		
2475		add: function(link) {
2476			if (typeof link.parameters === 'undefined') link.parameters = {};
2477			link.call = _boundcall;
2478			if (link.rel) ccms.ApiLinks.removeWithRel(link.rel);
2479			links.push(link);
2480		},
2481		
2482		addMany: function(links) {
2483			if (typeof links === 'object' && typeof links.foreach === 'function')
2484				links.foreach(this.add);
2485		},
2486		
2487		findByRel: function(rel) {
2488			return links[links.findBy(function(link) {
2489				if (typeof rel == 'string') return link.rel == rel;
2490				return link.rel.match(rel);
2491			})];
2492		},
2493		
2494		findWithRel: function(rel) {
2495			if (typeof rel == 'string')
2496				return links.filter(function(link) {return link.rel == rel;});
2497			else
2498				return links.filter(function(link) {return link.rel.match(rel);});
2499		},
2500		
2501		removeWithRel: function(rel) {
2502			if (typeof rel == 'string')
2503				links = links.filter(function(link) {return link.rel != rel;});
2504			else
2505				links = links.filter(function(link) {return !link.rel.match(rel);});
2506		},
2507		
2508		call: function(config) {
2509			var api;
2510			if (YAHOO.lang.isObject(api = config.api) || (api = this.findByRel(config.api))) {
2511				config.parseJSON = api.type.match('json');
2512				if (typeof config.url === 'undefined') config.url = api.href;
2513				if (typeof config.parameters === 'undefined') config.parameters = api.parameters;
2514				else if (typeof api.parameters === 'object') config.parameters = ccms.update(ccms.cloneOf(api.parameters), config.parameters);
2515				if (typeof config.parameters.jsi !== 'string') config.parameters.jsi = 'content';
2516				if (!config.url.match(/:\/\//) || -1 < config.url.indexOf(document.location.host)) {
2517					return ccms.async.http(config);
2518				}
2519				return ccms.async.jsr.call(config);
2520			}
2521		}
2522		
2523	};
2524})();
2525
2526/*
2527    http://www.JSON.org/json2.js
2528    2008-05-25
2529
2530    Public Domain.
2531
2532    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
2533
2534    See http://www.JSON.org/js.html
2535
2536    This file creates a global JSON object containing two methods: stringify
2537    and parse.
2538
2539        JSON.stringify(value, replacer, space)
2540            value       any JavaScript value, usually an object or array.
2541
2542            replacer    an optional parameter that determines how object
2543                        values are stringified for objects without a toJSON
2544                        method. It can be a function or an array.
2545
2546            space       an optional parameter that specifies the indentation
2547                        of nested structures. If it is omitted, the text will
2548                        be packed without extra whitespace. If it is a number,
2549                        it will specify the number of spaces to indent at each
2550                        level. If it is a string (such as '\t' or '&nbsp;'),
2551                        it contains the characters used to indent at each level.
2552
2553            This method produces a JSON text from a JavaScript value.
2554
2555            When an object value is found, if the object contains a toJSON
2556            method, its toJSON method will be called and the result will be
2557            stringified. A toJSON method does not serialize: it returns the
2558            value represented by the name/value pair that should be serialized,
2559            or undefined if nothing should be serialized. The toJSON method
2560            will be passed the key associated with the value, and this will be
2561            bound to the object holding the key.
2562
2563            For example, this would serialize Dates as ISO strings.
2564
2565                Date.prototype.toJSON = function (key) {
2566                    function f(n) {
2567                        // Format integers to have at least two digits.
2568                        return n < 10 ? '0' + n : n;
2569                    }
2570
2571                    return this.getUTCFullYear()   + '-' +
2572                         f(this.getUTCMonth() + 1) + '-' +
2573                         f(this.getUTCDate())      + 'T' +
2574                         f(this.getUTCHours())     + ':' +
2575                         f(this.getUTCMinutes())   + ':' +
2576                         f(this.getUTCSeconds())   + 'Z';
2577                };
2578
2579            You can provide an optional replacer method. It will be passed the
2580            key and value of each member, with this bound to the containing
2581            object. The value that is returned from your method will be
2582            serialized. If your method returns undefined, then the member will
2583            be excluded from the serialization.
2584
2585            If the replacer parameter is an array, then it will be used to
2586            select the members to be serialized. It filters the results such
2587            that only members with keys listed in the replacer array are
2588            stringified.
2589
2590            Values that do not have JSON representations, such as undefined or
2591            functions, will not be serialized. Such values in objects will be
2592            dropped; in arrays they will be replaced with null. You can use
2593            a replacer function to replace those with JSON values.
2594            JSON.stringify(undefined) returns undefined.
2595
2596            The optional space parameter produces a stringification of the
2597            value that is filled with line breaks and indentation to make it
2598            easier to read.
2599
2600            If the space parameter is a non-empty string, then that string will
2601            be used for indentation. If the space parameter is a number, then
2602            the indentation will be that many spaces.
2603
2604            Example:
2605
2606            text = JSON.stringify(['e', {pluribus: 'unum'}]);
2607            // text is '["e",{"pluribus":"unum"}]'
2608
2609
2610            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
2611            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
2612
2613            text = JSON.stringify([new Date()], function (key, value) {
2614                return this[key] instanceof Date ?
2615                    'Date(' + this[key] + ')' : value;
2616            });
2617            // text is '["Date(---current time---)"]'
2618
2619
2620        JSON.parse(text, reviver)
2621            This method parses a JSON text to produce an object or array.
2622            It can throw a SyntaxError exception.
2623
2624            The optional reviver parameter is a function that can filter and
2625            transform the results. It receives each of the keys and values,
2626            and its return value is used instead of the original value.
2627            If it returns what it received, then the structure is not modified.
2628            If it returns undefined then the member is deleted.
2629
2630            Example:
2631
2632            // Parse the text. Values that look like ISO date strings will
2633            // be converted to Date objects.
2634
2635            myData = JSON.parse(text, function (key, value) {
2636                var a;
2637                if (typeof value === 'string') {
2638                    a =
2639/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
2640                    if (a) {
2641                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
2642                            +a[5], +a[6]));
2643                    }
2644                }
2645                return value;
2646            });
2647
2648            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
2649                var d;
2650                if (typeof value === 'string' &&
2651                        value.slice(0, 5) === 'Date(' &&
2652                        value.slice(-1) === ')') {
2653                    d = new Date(value.slice(5, -1));
2654                    if (d) {
2655                        return d;
2656                    }
2657                }
2658                return value;
2659            });
2660
2661
2662    This is a reference implementation. You are free to copy, modify, or
2663    redistribute.
2664
2665    This code should be minified before deployment.
2666    See http://javascript.crockford.com/jsmin.html
2667
2668    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
2669    NOT CONTROL.
2670*/
2671
2672/*jslint evil: true */
2673
2674/*global JSON */
2675
2676/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", call,
2677    charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, getUTCMinutes,
2678    getUTCMonth, getUTCSeconds, hasOwnProperty, join, lastIndex, length,
2679    parse, propertyIsEnumerable, prototype, push, replace, slice, stringify,
2680    test, toJSON, toString
2681*/
2682
2683if (!this.JSON) {
2684
2685// Create a JSON object only if one does not already exist. We create the
2686// object in a closure to avoid creating global variables.
2687
2688    JSON = function () {
2689
2690        function f(n) {
2691            // Format integers to have at least two digits.
2692            return n < 10 ? '0' + n : n;
2693        }
2694
2695        Date.prototype.toJSON = function (key) {
2696
2697            return this.getUTCFullYear()   + '-' +
2698                 f(this.getUTCMonth() + 1) + '-' +
2699                 f(this.getUTCDate())      + 'T' +
2700                 f(this.getUTCHours())     + ':' +
2701                 f(this.getUTCMinutes())   + ':' +
2702                 f(this.getUTCSeconds())   + 'Z';
2703        };
2704
2705        var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
2706            escapeable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
2707            gap,
2708            indent,
2709            meta = {    // table of character substitutions
2710                '\b': '\\b',
2711                '\t': '\\t',
2712                '\n': '\\n',
2713                '\f': '\\f',
2714                '\r': '\\r',
2715                '"' : '\\"',
2716                '\\': '\\\\'
2717            },
2718            rep;
2719
2720
2721        function quote(string) {
2722
2723// If the string contains no control characters, no quote characters, and no
2724// backslash characters, then we can safely slap some quotes around it.
2725// Otherwise we must also replace the offending characters with safe escape
2726// sequences.
2727
2728            escapeable.lastIndex = 0;
2729            return escapeable.test(string) ?
2730                '"' + string.replace(escapeable, function (a) {
2731                    var c = meta[a];
2732                    if (typeof c === 'string') {
2733                        return c;
2734                    }
2735                    return '\\u' + ('0000' +
2736                            (+(a.charCodeAt(0))).toString(16)).slice(-4);
2737                }) + '"' :
2738                '"' + string + '"';
2739        }
2740
2741
2742        function str(key, holder) {
2743
2744// Produce a string from holder[key].
2745
2746            var i,          // The loop counter.
2747                k,          // The member key.
2748                v,          // The member value.
2749                length,
2750                mind = gap,
2751                partial,
2752                value = holder[key];
2753
2754// If the value has a toJSON method, call it to obtain a replacement value.
2755
2756            if (value && typeof value === 'object' &&
2757                    typeof value.toJSON === 'function') {
2758                value = value.toJSON(key);
2759            }
2760
2761// If we were called with a replacer function, then call the replacer to
2762// obtain a replacement value.
2763
2764            if (typeof rep === 'function') {
2765                value = rep.call(holder, key, value);
2766            }
2767
2768// What happens next depends on the value's type.
2769
2770            switch (typeof value) {
2771            case 'string':
2772                return quote(value);
2773
2774            case 'number':
2775
2776// JSON numbers must be finite. Encode non-finite numbers as null.
2777
2778                return isFinite(value) ? String(value) : 'null';
2779
2780            case 'boolean':
2781            case 'null':
2782
2783// If the value is a boolean or null, convert it to a string. Note:
2784// typeof null does not produce 'null'. The case is included here in
2785// the remote chance that this gets fixed someday.
2786
2787                return String(value);
2788
2789// If the type is 'object', we might be dealing with an object or an array or
2790// null.
2791
2792            case 'object':
2793
2794// Due to a specification blunder in ECMAScript, typeof null is 'object',
2795// so watch out for that case.
2796
2797                if (!value) {
2798                    return 'null';
2799                }
2800
2801// Make an array to hold the partial results of stringifying this object value.
2802
2803                gap += indent;
2804                partial = [];
2805
2806// If the object has a dontEnum length property, we'll treat it as an array.
2807
2808                if (typeof value.length === 'number' &&
2809                        !(value.propertyIsEnumerable('length'))) {
2810
2811// The object is an array. Stringify every element. Use null as a placeholder
2812// for non-JSON values.
2813
2814                    length = value.length;
2815                    for (i = 0; i < length; i += 1) {
2816                        partial[i] = str(i, value) || 'null';
2817                    }
2818
2819// Join all of the elements together, separated with commas, and wrap them in
2820// brackets.
2821
2822                    v = partial.length === 0 ? '[]' :
2823                        gap ? '[\n' + gap +
2824                                partial.join(',\n' + gap) + '\n' +
2825                                    mind + ']' :
2826                              '[' + partial.join(',') + ']';
2827                    gap = mind;
2828                    return v;
2829                }
2830
2831// If the replacer is an array, use it to select the members to be stringified.
2832
2833                if (rep && typeof rep === 'object') {
2834                    length = rep.length;
2835                    for (i = 0; i < length; i += 1) {
2836                        k = rep[i];
2837                        if (typeof k === 'string') {
2838                            v = str(k, value, rep);
2839                            if (v) {
2840                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
2841                            }
2842                        }
2843                    }
2844                } else {
2845
2846// Otherwise, iterate through all of the keys in the object.
2847
2848                    for (k in value) {
2849                        if (Object.hasOwnProperty.call(value, k)) {
2850                            v = str(k, value, rep);
2851                            if (v) {
2852                                partial.push(quote(k) + (gap ? ': ' : ':') + v);
2853                            }
2854                        }
2855                    }
2856                }
2857
2858// Join all of the member texts together, separated with commas,
2859// and wrap them in braces.
2860
2861                v = partial.length === 0 ? '{}' :
2862                    gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
2863                            mind + '}' : '{' + partial.join(',') + '}';
2864                gap = mind;
2865                return v;
2866            }
2867        }
2868
2869// Return the JSON object containing the stringify and parse methods.
2870
2871        return {
2872            stringify: function (value, replacer, space) {
2873
2874// The stringify method takes a value and an optional replacer, and an optional
2875// space parameter, and returns a JSON text. The replacer can be a function
2876// that can replace values, or an array of strings that will select the keys.
2877// A default replacer method can be provided. Use of the space parameter can
2878// produce text that is more easily readable.
2879
2880                var i;
2881                gap = '';
2882                indent = '';
2883
2884// If the space parameter is a number, make an indent string containing that
2885// many spaces.
2886
2887                if (typeof space === 'number') {
2888                    for (i = 0; i < space; i += 1) {
2889                        indent += ' ';
2890                    }
2891
2892// If the space parameter is a string, it will be used as the indent string.
2893
2894                } else if (typeof space === 'string') {
2895                    indent = space;
2896                }
2897
2898// If there is a replacer, it must be a function or an array.
2899// Otherwise, throw an error.
2900
2901                rep = replacer;
2902                if (replacer && typeof replacer !== 'function' &&
2903                        (typeof replacer !== 'object' ||
2904                         typeof replacer.length !== 'number')) {
2905                    throw new Error('JSON.stringify');
2906                }
2907
2908// Make a fake root object containing our value under the key of ''.
2909// Return the result of stringifying the value.
2910
2911                return str('', {'': value});
2912            },
2913
2914
2915            parse: function (text, reviver) {
2916
2917// The parse method takes a text and an optional reviver function, and returns
2918// a JavaScript value if the text is a valid JSON text.
2919
2920                var j;
2921
2922                function walk(holder, key) {
2923
2924// The walk method is used to recursively walk the resulting structure so
2925// that modifications can be made.
2926
2927                    var k, v, value = holder[key];
2928                    if (value && typeof value === 'object') {
2929                        for (k in value) {
2930                            if (Object.hasOwnProperty.call(value, k)) {
2931                                v = walk(value, k);
2932                                if (v !== undefined) {
2933                                    value[k] = v;
2934                                } else {
2935                                    delete value[k];
2936                                }
2937                            }
2938                        }
2939                    }
2940                    return reviver.call(holder, key, value);
2941                }
2942
2943
2944// Parsing happens in four stages. In the first stage, we replace certain
2945// Unicode characters with escape sequences. JavaScript handles many characters
2946// incorrectly, either silently deleting them, or treating them as line endings.
2947
2948                cx.lastIndex = 0;
2949                if (cx.test(text)) {
2950                    text = text.replace(cx, function (a) {
2951                        return '\\u' + ('0000' +
2952                                (+(a.charCodeAt(0))).toString(16)).slice(-4);
2953                    });
2954                }
2955
2956// In the second stage, we run the text against regular expressions that look
2957// for non-JSON patterns. We are especially concerned with '()' and 'new'
2958// because they can cause invocation, and '=' because it can cause mutation.
2959// But just to be safe, we want to reject all unexpected forms.
2960
2961// We split the second stage into 4 regexp operations in order to work around
2962// crippling inefficiencies in IE's and Safari's regexp engines. First we
2963// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
2964// replace all simple value tokens with ']' characters. Third, we delete all
2965// open brackets that follow a colon or comma or that begin the text. Finally,
2966// we look to see that the remaining characters are only whitespace or ']' or
2967// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
2968
2969                if (/^[\],:{}\s]*$/.
2970test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
2971replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
2972replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
2973
2974// In the third stage we use the eval function to compile the text into a
2975// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
2976// in JavaScript: it can begin a block or an object literal. We wrap the text
2977// in parens to eliminate the ambiguity.
2978
2979                    j = eval('(' + text + ')');
2980
2981// In the optional fourth stage, we recursively walk the new structure, passing
2982// each name/value pair to a reviver function for possible transformation.
2983
2984                    return typeof reviver === 'function' ?
2985                        walk({'': j}, '') : j;
2986                }
2987
2988// If the text is not JSON parseable, then a SyntaxError is thrown.
2989
2990                throw new SyntaxError('JSON.parse');
2991            }
2992        };
2993    }();
2994}
2995
2996ccms.extend(ccms.date, {
2997	monthNames: "January February March April May June July August September October November December".split(" "),
2998	weekdayNames: "Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" ")
2999});
3000
3001
3002/* http://delete.me.uk/2005/03/iso8601.html */
3003Date.prototype.setISO8601 = function (string) {
3004	var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
3005		"(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
3006		"(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
3007	var d = string.match(new RegExp(regexp));
3008
3009	var offset = 0;
3010	var date = new Date(d[1], 0, 1);
3011
3012	if (d[3]) { date.setMonth(d[3] - 1); }
3013	if (d[5]) { date.setDate(d[5]); }
3014	if (d[7]) { date.setHours(d[7]); }
3015	if (d[8]) { date.setMinutes(d[8]); }
3016	if (d[10]) { date.setSeconds(d[10]); }
3017	if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
3018	if (d[14]) {
3019		offset = (Number(d[16]) * 60) + Number(d[17]);
3020		offset *= ((d[15] == '-') ? 1 : -1);
3021	}
3022
3023	offset -= date.getTimezoneOffset();
3024	time = (Number(date) + (offset * 60 * 1000));
3025	this.setTime(Number(time));
3026};
3027Date.parseISO8601 = function(string) {
3028	var d = new Date();
3029	d.setISO8601(string);
3030	return d;
3031};

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.