PageSourceSearch

https://ufcw.ca/plugins/system/mootable/assets/js/mootools-more-1.6.2.js

js ufcw.ca collected 2026-10-02 02:33:19 UTC 385,273 bytes, 14,658 lines download raw bytes

1/* MooTools: the javascript framework. license: MIT-style license. copyright: Copyright (c) 2006-2023 [Valerio Proietti](https://mootools.net/).*/ 
2/*!
3Web Build: https://mootools.net/more/builder/a3048f4bfdf603b22a69c141dbd0fca9
4*/
5/*
6---
7
8script: More.js
9
10name: More
11
12description: MooTools More
13
14license: MIT-style license
15
16authors:
17  - Guillermo Rauch
18  - Thomas Aylott
19  - Scott Kyle
20  - Arian Stolwijk
21  - Tim Wienk
22  - Christoph Pojer
23  - Aaron Newton
24  - Jacob Thornton
25
26requires:
27  - Core/MooTools
28
29provides: [MooTools.More]
30
31...
32*/
33
34MooTools.More = {
35	version: '1.6.0',
36	build: '45b71db70f879781a7e0b0d3fb3bb1307c2521eb'
37};
38
39/*
40---
41
42script: Chain.Wait.js
43
44name: Chain.Wait
45
46description: value, Adds a method to inject pauses between chained events.
47
48license: MIT-style license.
49
50authors:
51  - Aaron Newton
52
53requires:
54  - Core/Chain
55  - Core/Element
56  - Core/Fx
57  - MooTools.More
58
59provides: [Chain.Wait]
60
61...
62*/
63
64(function(){
65
66var wait = {
67	wait: function(duration){
68		return this.chain(function(){
69			this.callChain.delay(duration == null ? 500 : duration, this);
70			return this;
71		}.bind(this));
72	}
73};
74
75Chain.implement(wait);
76
77if (this.Fx) Fx.implement(wait);
78
79if (this.Element && Element.implement && this.Fx){
80	Element.implement({
81
82		chains: function(effects){
83			Array.convert(effects || ['tween', 'morph', 'reveal']).each(function(effect){
84				effect = this.get(effect);
85				if (!effect) return;
86				effect.setOptions({
87					link:'chain'
88				});
89			}, this);
90			return this;
91		},
92
93		pauseFx: function(duration, effect){
94			this.chains(effect).get(effect || 'tween').wait(duration);
95			return this;
96		}
97
98	});
99}
100
101})();
102
103/*
104---
105
106script: Class.Binds.js
107
108name: Class.Binds
109
110description: Automagically binds specified methods in a class to the instance of the class.
111
112license: MIT-style license
113
114authors:
115  - Aaron Newton
116
117requires:
118  - Core/Class
119  - MooTools.More
120
121provides: [Class.Binds]
122
123...
124*/
125
126Class.Mutators.Binds = function(binds){
127	if (!this.prototype.initialize) this.implement('initialize', function(){});
128	return Array.convert(binds).concat(this.prototype.Binds || []);
129};
130
131Class.Mutators.initialize = function(initialize){
132	return function(){
133		Array.convert(this.Binds).each(function(name){
134			var original = this[name];
135			if (original) this[name] = original.bind(this);
136		}, this);
137		return initialize.apply(this, arguments);
138	};
139};
140
141/*
142---
143
144script: Class.Occlude.js
145
146name: Class.Occlude
147
148description: Prevents a class from being applied to a DOM element twice.
149
150license: MIT-style license.
151
152authors:
153  - Aaron Newton
154
155requires:
156  - Core/Class
157  - Core/Element
158  - MooTools.More
159
160provides: [Class.Occlude]
161
162...
163*/
164
165Class.Occlude = new Class({
166
167	occlude: function(property, element){
168		element = document.id(element || this.element);
169		var instance = element.retrieve(property || this.property);
170		if (instance && !this.occluded)
171			return (this.occluded = instance);
172
173		this.occluded = false;
174		element.store(property || this.property, this);
175		return this.occluded;
176	}
177
178});
179
180/*
181---
182
183script: Class.Refactor.js
184
185name: Class.Refactor
186
187description: Extends a class onto itself with new property, preserving any items attached to the class's namespace.
188
189license: MIT-style license
190
191authors:
192  - Aaron Newton
193
194requires:
195  - Core/Class
196  - MooTools.More
197
198# Some modules declare themselves dependent on Class.Refactor
199provides: [Class.refactor, Class.Refactor]
200
201...
202*/
203
204Class.refactor = function(original, refactors){
205
206	Object.each(refactors, function(item, name){
207		var origin = original.prototype[name];
208		origin = (origin && origin.$origin) || origin || function(){};
209		original.implement(name, (typeof item == 'function') ? function(){
210			var old = this.previous;
211			this.previous = origin;
212			var value = item.apply(this, arguments);
213			this.previous = old;
214			return value;
215		} : item);
216	});
217
218	return original;
219
220};
221
222/*
223---
224
225script: Class.Singleton.js
226
227name: Class.Singleton
228
229description: Always provides a single instance of a class
230
231license: MIT-style license.
232
233authors:
234  - Hristo Chakarov
235
236requires:
237  - Core/Class
238
239provides: [Class.Singleton]
240
241...
242*/
243
244Class.Singleton = new Class({
245
246	initialize : function(descriptor){
247		// here we keep reference of the single instance
248		var singleton;
249		// create a regular Class
250		var constructor = new Class(descriptor);
251		// We return another constructor, because we need to make sure that we
252		// always return the same one and only instance.
253		return function(){
254			if (singleton){
255				return singleton;
256			}
257			// Obviously we instantiate that class for the first time.
258			// Create brand new object & extend it with the prototype of the
259			// original `constructor`.
260			singleton = Object.append({}, constructor.prototype);
261			singleton.constructor = constructor;
262			// We also need to call the constructor as a function, passing the
263			// arguments object.
264			var returnValue = constructor.apply(singleton, arguments);
265			// In case the `constructor` returns something other than `this` -
266			// return that value; otherwise return the `singleton`.
267			singleton = typeof returnValue == 'object' ? returnValue : singleton;
268			return singleton;
269		};
270	}
271
272});
273
274/*
275---
276
277name: Events.Pseudos
278
279description: Adds the functionality to add pseudo events
280
281license: MIT-style license
282
283authors:
284  - Arian Stolwijk
285
286requires: [Core/Class.Extras, Core/Slick.Parser, MooTools.More]
287
288provides: [Events.Pseudos]
289
290...
291*/
292
293(function(){
294
295Events.Pseudos = function(pseudos, addEvent, removeEvent){
296
297	var storeKey = '_monitorEvents:';
298
299	var storageOf = function(object){
300		return {
301			store: object.store ? function(key, value){
302				object.store(storeKey + key, value);
303			} : function(key, value){
304				(object._monitorEvents || (object._monitorEvents = {}))[key] = value;
305			},
306			retrieve: object.retrieve ? function(key, dflt){
307				return object.retrieve(storeKey + key, dflt);
308			} : function(key, dflt){
309				if (!object._monitorEvents) return dflt;
310				return object._monitorEvents[key] || dflt;
311			}
312		};
313	};
314
315	var splitType = function(type){
316		if (type.indexOf(':') == -1 || !pseudos) return null;
317
318		var parsed = Slick.parse(type).expressions[0][0],
319			parsedPseudos = parsed.pseudos,
320			l = parsedPseudos.length,
321			splits = [];
322
323		while (l--){
324			var pseudo = parsedPseudos[l].key,
325				listener = pseudos[pseudo];
326			if (listener != null) splits.push({
327				event: parsed.tag,
328				value: parsedPseudos[l].value,
329				pseudo: pseudo,
330				original: type,
331				listener: listener
332			});
333		}
334		return splits.length ? splits : null;
335	};
336
337	return {
338
339		addEvent: function(type, fn, internal){
340			var split = splitType(type);
341			if (!split) return addEvent.call(this, type, fn, internal);
342
343			var storage = storageOf(this),
344				events = storage.retrieve(type, []),
345				eventType = split[0].event,
346				args = Array.slice(arguments, 2),
347				stack = fn,
348				self = this;
349
350			split.each(function(item){
351				var listener = item.listener,
352					stackFn = stack;
353				if (listener == false) eventType += ':' + item.pseudo + '(' + item.value + ')';
354				else stack = function(){
355					listener.call(self, item, stackFn, arguments, stack);
356				};
357			});
358
359			events.include({type: eventType, event: fn, monitor: stack});
360			storage.store(type, events);
361
362			if (type != eventType) addEvent.apply(this, [type, fn].concat(args));
363			return addEvent.apply(this, [eventType, stack].concat(args));
364		},
365
366		removeEvent: function(type, fn){
367			var split = splitType(type);
368			if (!split) return removeEvent.call(this, type, fn);
369
370			var storage = storageOf(this),
371				events = storage.retrieve(type);
372			if (!events) return this;
373
374			var args = Array.slice(arguments, 2);
375
376			removeEvent.apply(this, [type, fn].concat(args));
377			events.each(function(monitor, i){
378				if (!fn || monitor.event == fn) removeEvent.apply(this, [monitor.type, monitor.monitor].concat(args));
379				delete events[i];
380			}, this);
381
382			storage.store(type, events);
383			return this;
384		}
385
386	};
387
388};
389
390var pseudos = {
391
392	once: function(split, fn, args, monitor){
393		fn.apply(this, args);
394		this.removeEvent(split.event, monitor)
395			.removeEvent(split.original, fn);
396	},
397
398	throttle: function(split, fn, args){
399		if (!fn._throttled){
400			fn.apply(this, args);
401			fn._throttled = setTimeout(function(){
402				fn._throttled = false;
403			}, split.value || 250);
404		}
405	},
406
407	pause: function(split, fn, args){
408		clearTimeout(fn._pause);
409		fn._pause = fn.delay(split.value || 250, this, args);
410	}
411
412};
413
414Events.definePseudo = function(key, listener){
415	pseudos[key] = listener;
416	return this;
417};
418
419Events.lookupPseudo = function(key){
420	return pseudos[key];
421};
422
423var proto = Events.prototype;
424Events.implement(Events.Pseudos(pseudos, proto.addEvent, proto.removeEvent));
425
426['Request', 'Fx'].each(function(klass){
427	if (this[klass]) this[klass].implement(Events.prototype);
428});
429
430})();
431
432/*
433---
434
435script: Drag.js
436
437name: Drag
438
439description: The base Drag Class. Can be used to drag and resize Elements using mouse events.
440
441license: MIT-style license
442
443authors:
444  - Valerio Proietti
445  - Tom Occhinno
446  - Jan Kassens
447
448requires:
449  - Core/Events
450  - Core/Options
451  - Core/Element.Event
452  - Core/Element.Style
453  - Core/Element.Dimensions
454  - MooTools.More
455
456provides: [Drag]
457...
458
459*/
460(function(){
461
462var Drag = this.Drag = new Class({
463
464	Implements: [Events, Options],
465
466	options: {/*
467		onBeforeStart: function(thisElement){},
468		onStart: function(thisElement, event){},
469		onSnap: function(thisElement){},
470		onDrag: function(thisElement, event){},
471		onCancel: function(thisElement){},
472		onComplete: function(thisElement, event){},*/
473		snap: 6,
474		unit: 'px',
475		grid: false,
476		style: true,
477		limit: false,
478		handle: false,
479		invert: false,
480		unDraggableTags: ['button', 'input', 'a', 'textarea', 'select', 'option'],
481		preventDefault: false,
482		stopPropagation: false,
483		compensateScroll: false,
484		modifiers: {x: 'left', y: 'top'}
485	},
486
487	initialize: function(){
488		var params = Array.link(arguments, {
489			'options': Type.isObject,
490			'element': function(obj){
491				return obj != null;
492			}
493		});
494
495		this.element = document.id(params.element);
496		this.document = this.element.getDocument();
497		this.setOptions(params.options || {});
498		var htype = typeOf(this.options.handle);
499		this.handles = ((htype == 'array' || htype == 'collection') ? $$(this.options.handle) : document.id(this.options.handle)) || this.element;
500		this.mouse = {'now': {}, 'pos': {}};
501		this.value = {'start': {}, 'now': {}};
502		this.offsetParent = (function(el){
503			var offsetParent = el.getOffsetParent();
504			var isBody = !offsetParent || (/^(?:body|html)$/i).test(offsetParent.tagName);
505			return isBody ? window : document.id(offsetParent);
506		})(this.element);
507		this.selection = 'selectstart' in document ? 'selectstart' : 'mousedown';
508
509		this.compensateScroll = {start: {}, diff: {}, last: {}};
510
511		if ('ondragstart' in document && !('FileReader' in window) && !Drag.ondragstartFixed){
512			document.ondragstart = Function.convert(false);
513			Drag.ondragstartFixed = true;
514		}
515
516		this.bound = {
517			start: this.start.bind(this),
518			check: this.check.bind(this),
519			drag: this.drag.bind(this),
520			stop: this.stop.bind(this),
521			cancel: this.cancel.bind(this),
522			eventStop: Function.convert(false),
523			scrollListener: this.scrollListener.bind(this)
524		};
525		this.attach();
526	},
527
528	attach: function(){
529		this.handles.addEvent('mousedown', this.bound.start);
530		this.handles.addEvent('touchstart', this.bound.start);
531		if (this.options.compensateScroll) this.offsetParent.addEvent('scroll', this.bound.scrollListener);
532		return this;
533	},
534
535	detach: function(){
536		this.handles.removeEvent('mousedown', this.bound.start);
537		this.handles.removeEvent('touchstart', this.bound.start);
538		if (this.options.compensateScroll) this.offsetParent.removeEvent('scroll', this.bound.scrollListener);
539		return this;
540	},
541
542	scrollListener: function(){
543
544		if (!this.mouse.start) return;
545		var newScrollValue = this.offsetParent.getScroll();
546
547		if (this.element.getStyle('position') == 'absolute'){
548			var scrollDiff = this.sumValues(newScrollValue, this.compensateScroll.last, -1);
549			this.mouse.now = this.sumValues(this.mouse.now, scrollDiff, 1);
550		} else {
551			this.compensateScroll.diff = this.sumValues(newScrollValue, this.compensateScroll.
551start, -1);
552		}
553		if (this.offsetParent != window) this.compensateScroll.diff = this.sumValues(this.compensateScroll.start, newScrollValue, -1);
554		this.compensateScroll.last = newScrollValue;
555		this.render(this.options);
556	},
557
558	sumValues: function(alpha, beta, op){
559		var sum = {}, options = this.options;
560		for (var z in options.modifiers){
561			if (!options.modifiers[z]) continue;
562			sum[z] = alpha[z] + beta[z] * op;
563		}
564		return sum;
565	},
566
567	start: function(event){
568		if (this.options.unDraggableTags.contains(event.target.get('tag'))) return;
569
570		var options = this.options;
571
572		if (event.rightClick) return;
573
574		if (options.preventDefault) event.preventDefault();
575		if (options.stopPropagation) event.stopPropagation();
576		this.compensateScroll.start = this.compensateScroll.last = this.offsetParent.getScroll();
577		this.compensateScroll.diff = {x: 0, y: 0};
578		this.mouse.start = event.page;
579		this.fireEvent('beforeStart', this.element);
580
581		var limit = options.limit;
582		this.limit = {x: [], y: []};
583
584		var z, coordinates, offsetParent = this.offsetParent == window ? null : this.offsetParent;
585		for (z in options.modifiers){
586			if (!options.modifiers[z]) continue;
587
588			var style = this.element.getStyle(options.modifiers[z]);
589
590			// Some browsers (IE and Opera) don't always return pixels.
591			if (style && !style.match(/px$/)){
592				if (!coordinates) coordinates = this.element.getCoordinates(offsetParent);
593				style = coordinates[options.modifiers[z]];
594			}
595
596			if (options.style) this.value.now[z] = (style || 0).toInt();
597			else this.value.now[z] = this.element[options.modifiers[z]];
598
599			if (options.invert) this.value.now[z] *= -1;
600
601			this.mouse.pos[z] = event.page[z] - this.value.now[z];
602
603			if (limit && limit[z]){
604				var i = 2;
605				while (i--){
606					var limitZI = limit[z][i];
607					if (limitZI || limitZI === 0) this.limit[z][i] = (typeof limitZI == 'function') ? limitZI() : limitZI;
608				}
609			}
610		}
611
612		if (typeOf(this.options.grid) == 'number') this.options.grid = {
613			x: this.options.grid,
614			y: this.options.grid
615		};
616
617		var events = {
618			mousemove: this.bound.check,
619			mouseup: this.bound.cancel,
620			touchmove: this.bound.check,
621			touchend: this.bound.cancel
622		};
623		events[this.selection] = this.bound.eventStop;
624		this.document.addEvents(events);
625	},
626
627	check: function(event){
628		if (this.options.preventDefault) event.preventDefault();
629		var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2)));
630		if (distance > this.options.snap){
631			this.cancel();
632			this.document.addEvents({
633				mousemove: this.bound.drag,
634				mouseup: this.bound.stop,
635				touchmove: this.bound.drag,
636				touchend: this.bound.stop
637			});
638			this.fireEvent('start', [this.element, event]).fireEvent('snap', this.element);
639		}
640	},
641
642	drag: function(event){
643		var options = this.options;
644		if (options.preventDefault) event.preventDefault();
645		this.mouse.now = this.sumValues(event.page, this.compensateScroll.diff, -1);
646
647		this.render(options);
648		this.fireEvent('drag', [this.element, event]);
649	},
650
651	render: function(options){
652		for (var z in options.modifiers){
653			if (!options.modifiers[z]) continue;
654			this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z];
655
656			if (options.invert) this.value.now[z] *= -1;
657			if (options.limit && this.limit[z]){
658				if ((this.limit[z][1] || this.limit[z][1] === 0) && (this.value.now[z] > this.limit[z][1])){
659					this.value.now[z] = this.limit[z][1];
660				} else if ((this.limit[z][0] || this.limit[z][0] === 0) && (this.value.now[z] < this.limit[z][0])){
661					this.value.now[z] = this.limit[z][0];
662				}
663			}
664			if (options.grid[z]) this.value.now[z] -= ((this.value.now[z] - (this.limit[z][0]||0)) % options.grid[z]);
665			if (options.style) this.element.setStyle(options.modifiers[z], this.value.now[z] + options.unit);
666			else this.element[options.modifiers[z]] = this.value.now[z];
667		}
668	},
669
670	cancel: function(event){
671		this.document.removeEvents({
672			mousemove: this.bound.check,
673			mouseup: this.bound.cancel,
674			touchmove: this.bound.check,
675			touchend: this.bound.cancel
676		});
677		if (event){
678			this.document.removeEvent(this.selection, this.bound.eventStop);
679			this.fireEvent('cancel', this.element);
680		}
681	},
682
683	stop: function(event){
684		var events = {
685			mousemove: this.bound.drag,
686			mouseup: this.bound.stop,
687			touchmove: this.bound.drag,
688			touchend: this.bound.stop
689		};
690		events[this.selection] = this.bound.eventStop;
691		this.document.removeEvents(events);
692		this.mouse.start = null;
693		if (event) this.fireEvent('complete', [this.element, event]);
694	}
695
696});
697
698})();
699
700
701Element.implement({
702
703	makeResizable: function(options){
704		var drag = new Drag(this, Object.merge({
705			modifiers: {
706				x: 'width',
707				y: 'height'
708			}
709		}, options));
710
711		this.store('resizer', drag);
712		return drag.addEvent('drag', function(){
713			this.fireEvent('resize', drag);
714		}.bind(this));
715	}
716
717});
718
719/*
720---
721
722script: Drag.Move.js
723
724name: Drag.Move
725
726description: A Drag extension that provides support for the constraining of draggables to containers and droppables.
727
728license: MIT-style license
729
730authors:
731  - Valerio Proietti
732  - Tom Occhinno
733  - Jan Kassens
734  - Aaron Newton
735  - Scott Kyle
736
737requires:
738  - Core/Element.Dimensions
739  - Drag
740
741provides: [Drag.Move]
742
743...
744*/
745
746Drag.Move = new Class({
747
748	Extends: Drag,
749
750	options: {/*
751		onEnter: function(thisElement, overed){},
752		onLeave: function(thisElement, overed){},
753		onDrop: function(thisElement, overed, event){},*/
754		droppables: [],
755		container: false,
756		precalculate: false,
757		includeMargins: true,
758		checkDroppables: true
759	},
760
761	initialize: function(element, options){
762		this.parent(element, options);
763		element = this.element;
764
765		this.droppables = $$(this.options.droppables);
766		this.setContainer(this.options.container);
767
768		if (this.options.style){
769			if (this.options.modifiers.x == 'left' && this.options.modifiers.y == 'top'){
770				var parent = element.getOffsetParent(),
771					styles = element.getStyles('left', 'top');
772				if (parent && (styles.left == 'auto' || styles.top == 'auto')){
773					element.setPosition(element.getPosition(parent));
774				}
775			}
776
777			if (element.getStyle('position') == 'static') element.setStyle('position', 'absolute');
778		}
779
780		this.addEvent('start', this.checkDroppables, true);
781		this.overed = null;
782	},
783
784	setContainer: function(container){
785		this.container = document.id(container);
786		if (this.container && typeOf(this.container) != 'element'){
787			this.container = document.id(this.container.getDocument().body);
788		}
789	},
790
791	start: function(event){
792		if (this.container) this.options.limit = this.calculateLimit();
793
794		if (this.options.precalculate){
795			this.positions = this.droppables.map(function(el){
796				return el.getCoordinates();
797			});
798		}
799
800		this.parent(event);
801	},
802
803	calculateLimit: function(){
804		var element = this.element,
805			container = this.container,
806
807			offsetParent = document.id(element.getOffsetParent()) || document.body,
808			containerCoordinates = container.getCoordinates(offsetParent),
809			elementMargin = {},
810			elementBorder = {},
811			containerMargin = {},
812			containerBorder = {},
813			offsetParentPadding = {},
814			offsetScroll = offsetParent.getScroll();
815
816		['top', 'right', 'bottom', 'left'].each(function(pad){
817			elementMargin[pad] = element.getStyle('margin-' + pad).toInt();
818			elementBorder[pad] = element.getStyle('border-' + pad).toInt();
819			containerMargin[pad] = container.getStyle('margin-' + pad).toInt();
820			containerBorder[pad] = container.getStyle('border-' + pad).toInt();
821			offsetParentPadding[pad] = offsetParent.getStyle('padding-' + pad).toInt();
822		}, this);
823
824		var width = element.offsetWidth + elementMargin.left + elementMargin.right,
825			height = element.offsetHeight + elementMargin.top + elementMargin.bottom,
826			left = 0 + offsetScroll.x,
827			top = 0 + offsetScroll.y,
828			right = containerCoordinates.right - containerBorder.right - width + offsetScroll.x,
829			bottom = containerCoordinates.bottom - containerBorder.bottom - height + offsetScroll.y;
830
831		if (this.options.includeMargins){
832			left += elementMargin.left;
833			top += elementMargin.top;
834		} else {
835			right += elementMargin.right;
836			bottom += elementMargin.bottom;
837		}
838
839		if (element.getStyle('position') == 'relative'){
840			var coords = element.getCoordinates(offsetParent);
841			coords.left -= element.getStyle('left').toInt();
842			coords.top -= element.getStyle('top').toInt();
843
844			left -= coords.left;
845			top -= coords.top;
846			if (container.getStyle('position') != 'relative'){
847				left += containerBorder.left;
848				top += containerBorder.top;
849			}
850			right += elementMargin.left - coords.left;
851			bottom += elementMargin.top - coords.top;
852
853			if (container != offsetParent){
854				left += containerMargin.left + offsetParentPadding.left;
855				if (!offsetParentPadding.left && left < 0) left = 0;
856				top += offsetParent == document.body ? 0 : containerMargin.top + offsetParentPadding.top;
857				if (!offsetParentPadding.top && top < 0) top = 0;
858			}
859		} else {
860			left -= elementMargin.left;
861			top -= elementMargin.top;
862			if (container != offsetParent){
863				left += containerCoordinates.left + containerBorder.left;
864				top += containerCoordinates.top + containerBorder.top;
865			}
866		}
867
868		return {
869			x: [left, right],
870			y: [top, bottom]
871		};
872	},
873
874	getDroppableCoordinates: function(element){
875		var position = element.getCoordinates();
876		if (element.getStyle('position') == 'fixed'){
877			var scroll = window.getScroll();
878			position.left += scroll.x;
879			position.right += scroll.x;
880			position.top += scroll.y;
881			position.bottom += scroll.y;
882		}
883		return position;
884	},
885
886	checkDroppables: function(){
887		var overed = this.droppables.filter(function(el, i){
888			el = this.positions ? this.positions[i] : this.getDroppableCoordinates(el);
889			var now = this.mouse.now;
890			return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top);
891		}, this).getLast();
892
893		if (this.overed != overed){
894			if (this.overed) this.fireEvent('leave', [this.element, this.overed]);
895			if (overed) this.fireEvent('enter', [this.element, overed]);
896			this.overed = overed;
897		}
898	},
899
900	drag: function(event){
901		this.parent(event);
902		if (this.options.checkDroppables && this.droppables.length) this.checkDroppables();
903	},
904
905	stop: function(event){
906		this.checkDroppables();
907		this.fireEvent('drop', [this.element, this.overed, event]);
908		this.overed = null;
909		return this.parent(event);
910	}
911
912});
913
914Element.implement({
915
916	makeDraggable: function(options){
917		var drag = new Drag.Move(this, options);
918		this.store('dragger', drag);
919		return drag;
920	}
921
922});
923
924/*
925---
926
927script: Element.Measure.js
928
929name: Element.Measure
930
931description: Extends the Element native object to include methods useful in measuring dimensions.
932
933credits: "Element.measure / .expose methods by Daniel Steigerwald License: MIT-style license. Copyright: Copyright (c) 2008 Daniel Steigerwald, daniel.steigerwald.cz"
934
935license: MIT-style license
936
937authors:
938  - Aaron Newton
939
940requires:
941  - Core/Element.Style
942  - Core/Element.Dimensions
943  - MooTools.More
944
945provides: [Element.Measure]
946
947...
948*/
949
950(function(){
951
952var getStylesList = function(styles, planes){
953	var list = [];
954	Object.each(planes, function(directions){
955		Object.each(directions, function(edge){
956			styles.each(function(style){
957				list.push(style + '-' + edge + (style == 'border' ? '-width' : ''));
958			});
959		});
960	});
961	return list;
962};
963
964var calculateEdgeSize = function(edge, styles){
965	var total = 0;
966	Object.each(styles, function(value, style){
967		if (style.test(edge)) total = total + value.toInt();
968	});
969	return total;
970};
971
972var isVisible = function(el){
973	return !!(!el || el.offsetHeight || el.offsetWidth);
974};
975
976
977Element.implement({
978
979	measure: function(fn){
980		if (isVisible(this)) return fn.call(this);
981		var parent = this.getParent(),
982			toMeasure = [];
983		while (!isVisible(parent) && parent != document.body){
984			toMeasure.push(parent.expose());
985			parent = parent.getParent();
986		}
987		var restore = this.expose(),
988			result = fn.call(this);
989		restore();
990		toMeasure.each(function(restore){
991			restore();
992		});
993		return result;
994	},
995
996	expose: function(){
997		if (this.getStyle('display') != 'none') return function(){};
998		var before = this.style.cssText;
999		this.setStyles({
1000			display: 'block',
1001			position: 'absolute',
1002			visibility: 'hidden'
1003		});
1004		return function(){
1005			this.style.cssText = before;
1006		}.bind(this);
1007	},
1008
1009	getDimensions: function(options){
1010		options = Object.merge({computeSize: false}, options);
1011		var dim = {x: 0, y: 0};
1012
1013		var getSize = function(el, options){
1014			return (options.computeSize) ? el.getComputedSize(options) : el.getSize();
1015		};
1016
1017		var parent = this.getParent('body');
1018
1019		if (parent && this.getStyle('display') == 'none'){
1020			dim = this.measure(function(){
1021				return getSize(this, options);
1022			});
1023		} else if (parent){
1024			try { //safari sometimes crashes here, so catch it
1025				dim = getSize(this, options);
1026			} catch (e){}
1027		}
1028
1029		return Object.append(dim, (dim.x || dim.x === 0) ? {
1030			width: dim.x,
1031			height: dim.y
1032		} : {
1033			x: dim.width,
1034			y: dim.height
1035		});
1036	},
1037
1038	getComputedSize: function(options){
1039		
1040
1041		options = Object.merge({
1042			styles: ['padding','border'],
1043			planes: {
1044				height: ['top','bottom'],
1045				width: ['left','right']
1046			},
1047			mode: 'both'
1048		}, options);
1049
1050		var styles = {},
1051			size = {width: 0, height: 0},
1052			dimensions;
1053
1054		if (options.mode == 'vertical'){
1055			delete size.width;
1056			delete options.planes.width;
1057		} else if (options.mode == 'horizontal'){
1058			delete size.height;
1059			delete options.planes.height;
1060		}
1061
1062		getStylesList(options.styles, options.planes).each(function(style){
1063			styles[style] = this.getStyle(style).toInt();
1064		}, this);
1065
1066		Object.each(options.planes, function(edges, plane){
1067
1068			var capitalized = plane.capitalize(),
1069				style = this.getStyle(plane);
1070
1071			if (style == 'auto' && !dimensions) dimensions = this.getDimensions();
1072
1073			style = styles[plane] = (style == 'auto') ? dimensions[plane] : style.toInt();
1074			size['total' + capitalized] = style;
1075
1076			edges.each(function(edge){
1077				var edgesize = calculateEdgeSize(edge, styles);
1078				size['computed' + edge.capitalize()] = edgesize;
1079				size['total' + capitalized] += edgesize;
1080			});
1081
1082		}, this);
1083
1084		return Object.append(size, styles);
1085	}
1086
1087});
1088
1089})();
1090
1091/*
1092---
1093
1094script: Slider.js
1095
1096name: Slider
1097
1098description: Class for creating horizontal and vertical slider controls.
1099
1100license: MIT-style license
1101
1102authors:
1103  - Valerio Proietti
1104
1105requires:
1106  - Core/Element.Dimensions
1107  - Core/Number
1108  - Class.Binds
1109  - Drag
1110  - Element.Measure
1111
1112provides: [Slider]
1113
1114...
1115*/
1116(function(){
1117
1118var Slider = this.Slider = new Class({
1119
1120	Implements: [Events, Options],
1121
1122	Binds: ['clickedElement', 'draggedKnob', 'scrolledElement'],
1123
1124	options: {/*
1125		onTick: function(intPosition){},
1126		onMove: function(){},
1127		onChange: function(intStep){},
1128		onComplete: function(strStep){},*/
1129		onTick: function(position){
1130			this.setKnobPosition(position);
1131		},
1132		initialStep: 0,
1133		snap: false,
1134		offset: 0,
1135		range: false,
1136		wheel: false,
1137		steps: 100,
1138		mode: 'horizontal'
1139	},
1140
1141	initialize: function(element, knob, options){
1142		this.setOptions(options);
1143		options = this.options;
1144		this.element = document.id(element);
1145		knob = this.knob = document.id(knob);
1146		this.previousChange = this.previousEnd = this.step = options.initialStep ? options.initialStep : options.range ? options.range[0] : 0;
1147
1148		var limit = {},
1149			modifiers = {x: false, y: false};
1150
1151		switch (options.mode){
1152			case 'vertical':
1153				this.axis = 'y';
1154				this.property = 'top';
1155				this.offset = 'offsetHeight';
1156				break;
1157			case 'horizontal':
1158				this.axis = 'x';
1159				this.property = 'left';
1160				this.offset = 'offsetWidth';
1161		}
1162
1163		this.setSliderDimensions();
1164		this.setRange(options.range, null, true);
1165
1166		if (knob.getStyle('position') == 'static') knob.setStyle('position', 'relative');
1167		knob.setStyle(this.property, -options.offset);
1168		modifiers[this.axis] = this.property;
1169		limit[this.axis] = [-options.offset, this.full - options.offset];
1170
1171		var dragOptions = {
1172			snap: 0,
1173			limit: limit,
1174			modifiers: modifiers,
1175			onDrag: this.draggedKnob,
1176			onStart: this.draggedKnob,
1177			onBeforeStart: (function(){
1178				this.isDragging = true;
1179			}).bind(this),
1180			onCancel: function(){
1181				this.isDragging = false;
1182			}.bind(this),
1183			onComplete: function(){
1184				this.isDragging = false;
1185				this.draggedKnob();
1186				this.end();
1187			}.bind(this)
1188		};
1189		if (options.snap) this.setSnap(dragOptions);
1190
1191		this.drag = new Drag(knob, dragOptions);
1192		if (options.initialStep != null) this.set(options.initialStep, true);
1193		this.attach();
1194	},
1195
1196	attach: function(){
1197		this.element.addEvent('mousedown', this.clickedElement);
1198		if (this.options.wheel) this.element.addEvent('mousewheel', this.scrolledElement);
1199		this.drag.attach();
1200		return this;
1201	},
1202
1203	detach: function(){
1204		this.element.removeEvent('mousedown', this.clickedElement)
1205			.removeEvent('mousewheel', this.scrolledElement);
1206		this.drag.detach();
1207		return this;
1208	},
1209
1210	autosize: function(){
1211		this.setSliderDimensions()
1212			.setKnobPosition(this.toPosition(this.step));
1213		this.drag.options.limit[this.axis] = [-this.options.offset, this.full - this.options.offset];
1214		if (this.options.snap) this.setSnap();
1215		return this;
1216	},
1217
1218	setSnap: function(options){
1219		if (!options) options = this.drag.options;
1220		options.grid = Math.ceil(this.stepWidth);
1221		options.limit[this.axis][1] = this.element[this.offset];
1222		return this;
1223	},
1224
1225	setKnobPosition: function(position){
1226		if (this.options.snap) position = this.toPosition(this.step);
1227		this.knob.setStyle(this.property, position);
1228		return this;
1229	},
1230
1231	setSliderDimensions: function(){
1232		this.full = this.element.measure(function(){
1233			this.half = this.knob[this.offset] / 2;
1234			return this.element[this.offset] - this.knob[this.offset] + (this.options.offset * 2);
1235		}.bind(this));
1236		return this;
1237	},
1238
1239	set: function(step, silently){
1240		if (!((this.range > 0) ^ (step < this.min))) step = this.min;
1241		if (!((this.range > 0) ^ (step > this.max))) step = this.max;
1242
1243		this.step = (step).round(this.modulus.decimalLength);
1244		if (silently) this.checkStep().setKnobPosition(this.toPosition(this.step));
1245		else this.checkStep().fireEvent('tick', this.toPosition(this.step)).fireEvent('move').end();
1246		return this;
1247	},
1248
1249	setRange: function(range, pos, silently){
1250		this.min = Array.pick([range[0], 0]);
1251		this.max = Array.pick([range[1], this.options.steps]);
1252		this.range = this.max - this.min;
1253		this.steps = this.options.steps || this.full;
1254		var stepSize = this.stepSize = Math.abs(this.range) / this.steps;
1255		this.stepWidth = this.stepSize * this.full / Math.abs(this.range);
1256		this.setModulus();
1257
1258		if (range) this.set(Array.pick([pos, this.step]).limit(this.min,this.max), silently);
1259		return this;
1260	},
1261
1262	setModulus: function(){
1263		var decimals = ((this.stepSize + '').split('.')[1] || []).length,
1264			modulus = 1 + '';
1265		while (decimals--) modulus += '0';
1266		this.modulus = {multiplier: (modulus).toInt(10), decimalLength: modulus.length - 1};
1267	},
1268
1269	clickedElement: function(event){
1270		if (this.isDragging || event.target == this.knob) return;
1271
1272		var dir = this.range < 0 ? -1 : 1,
1273			position = event.page[this.axis] - this.element.getPosition()[this.axis] - this.half;
1274
1275		position = position.limit(-this.options.offset, this.full - this.options.offset);
1276
1277		this.step = (this.min + dir * this.toStep(position)).round(this.modulus.decimalLength);
1278
1279		this.checkStep()
1280			.fireEvent('tick', position)
1281			.fireEvent('move')
1282			.end();
1283	},
1284
1285	scrolledElement: function(event){
1286		var mode = (this.options.mode == 'horizontal') ? (event.wheel < 0) : (event.wheel > 0);
1287		this.set(this.step + (mode ? -1 : 1) * this.stepSize);
1288		event.stop();
1289	},
1290
1291	draggedKnob: function(){
1292		var dir = this.range < 0 ? -1 : 1,
1293			position = this.drag.value.now[this.axis];
1294
1295		position = position.limit(-this.options.offset, this.full -this.options.offset);
1296
1297		this.step = (this.min + dir * this.toStep(position)).round(this.modulus.decimalLength);
1298		this.checkStep();
1299		this.fireEvent('move');
1300	},
1301
1302	checkStep: function(){
1303		var step = this.step;
1304		if (this.previousChange != step){
1305			this.previousChange = step;
1306			this.fireEvent('change', step);
1307		}
1308		return this;
1309	},
1310
1311	end: function(){
1312		var step = this.step;
1313		if (this.previousEnd !== step){
1314			this.previousEnd = step;
1315			this.fireEvent('complete', step + '');
1316		}
1317		return this;
1318	},
1319
1320	toStep: function(position){
1321		var step = (position + this.options.offset) * this.stepSize / this.full * this.steps;
1322		return this.options.steps ? (step - (step * this.modulus.multiplier) % (this.stepSize * this.modulus.multiplier) / this.modulus.multiplier).round(this.modulus.decimalLength) : step;
1323	},
1324
1325	toPosition: function(step){
1326		return (this.full * Math.abs(this.min - step)) / (this.steps * this.stepSize) - this.options.offset || 0;
1327	}
1328
1329});
1330
1331})();
1332
1333
1334/*
1335---
1336
1337script: Sortables.js
1338
1339name: Sortables
1340
1341description: Class for creating a drag and drop sorting interface for lists of items.
1342
1343license: MIT-style license
1344
1345authors:
1346  - Tom Occhino
1347
1348requires:
1349  - Core/Fx.Morph
1350  - Drag.Move
1351
1352provides: [Sortables]
1353
1354...
1355*/
1356(function(){
1357
1358var Sortables = this.Sortables = new Class({
1359
1360	Implements: [Events, Options],
1361
1362	options: {/*
1363		onSort: function(element, clone){},
1364		onStart: function(element, clone){},
1365		onComplete: function(element){},*/
1366		opacity: 1,
1367		clone: false,
1368		revert: false,
1369		handle: false,
1370		dragOptions: {},
1371		unDraggableTags: ['button', 'input', 'a', 'textarea', 'select', 'option']
1372	},
1373
1374	initialize: function(lists, options){
1375		this.setOptions(options);
1376
1377		this.elements = [];
1378		this.lists = [];
1379		this.idle = true;
1380
1381		this.addLists($$(document.id(lists) || lists));
1382
1383		if (!this.options.clone) this.options.revert = false;
1384		if (this.options.revert) this.effect = new Fx.Morph(null, Object.merge({
1385			duration: 250,
1386			link: 'cancel'
1387		}, this.options.revert));
1388	},
1389
1390	attach: function(){
1391		this.addLists(this.lists);
1392		return this;
1393	},
1394
1395	detach: function(){
1396		this.lists = this.removeLists(this.lists);
1397		return this;
1398	},
1399
1400	addItems: function(){
1401		Array.flatten(arguments).each(function(element){
1402			this.elements.push(element);
1403			var start = element.retrieve('sortables:start', function(event){
1404				this.start.call(this, event, element);
1405			}.bind(this));
1406			(this.options.handle ? element.getElement(this.options.handle) || element : element).addEvent('mousedown', start);
1407		}, this);
1408		return this;
1409	},
1410
1411	addLists: function(){
1412		Array.flatten(arguments).each(function(list){
1413			this.lists.include(list);
1414			this.addItems(list.getChildren());
1415		}, this);
1416		return this;
1417	},
1418
1419	removeItems: function(){
1420		return $$(Array.flatten(arguments).map(function(element){
1421			this.elements.erase(element);
1422			var start = element.retrieve('sortables:start');
1423			(this.options.handle ? element.getElement(this.options.handle) || element : element).removeEvent('mousedown', start);
1424
1425			return element;
1426		}, this));
1427	},
1428
1429	removeLists: function(){
1430		return $$(Array.flatten(arguments).map(function(list){
1431			this.lists.erase(list);
1432			this.removeItems(list.getChildren());
1433
1434			return list;
1435		}, this));
1436	},
1437
1438	getDroppableCoordinates: function(element){
1439		var offsetParent = element.getOffsetParent();
1440		var position = element.getPosition(offsetParent);
1441		var scroll = {
1442			w: window.getScroll(),
1443			offsetParent: offsetParent.getScroll()
1444		};
1445		position.x += scroll.offsetParent.x;
1446		position.y += scroll.offsetParent.y;
1447
1448		if (offsetParent.getStyle('position') == 'fixed'){
1449			position.x -= scroll.w.x;
1450			position.y -= scroll.w.y;
1451		}
1452
1453		return position;
1454	},
1455
1456	getClone: function(event, element){
1457		if (!this.options.clone) return new Element(element.tagName).inject(document.body);
1458		if (typeOf(this.options.clone) == 'function') return this.options.clone.call(this, event, element, this.list);
1459		var clone = element.clone(true).setStyles({
1460			margin: 0,
1461			position: 'absolute',
1462			visibility: 'hidden',
1463			width: element.getStyle('width')
1464		}).addEvent('mousedown', function(event){
1465			element.fireEvent('mousedown', event);
1466		});
1467		//prevent the duplicated radio inputs from unchecking the real one
1468		if (clone.get('html').test('radio')){
1469			clone.getElements('input[type=radio]').each(function(input, i){
1470				input.set('name', 'clone_' + i);
1471				if (input.get('checked')) element.getElements('input[type=radio]')[i].set('checked', true);
1472			});
1473		}
1474
1475		return clone.inject(this.list).setPosition(this.getDroppableCoordinates(this.element));
1476	},
1477
1478	getDroppables: function(){
1479		var droppables = this.list.getChildren().erase(this.clone).erase(this.element);
1480		if (!this.options.constrain) droppables.append(this.lists).erase(this.list);
1481		return droppables;
1482	},
1483
1484	insert: function(dragging, element){
1485		var where = 'inside';
1486		if (this.lists.contains(element)){
1487			this.list = element;
1488			this.drag.droppables = this.getDroppables();
1489		} else {
1490			where = this.element.getAllPrevious().contains(element) ? 'before' : 'after';
1491		}
1492		this.element.inject(element, where);
1493		this.fireEvent('sort', [this.element, this.clone]);
1494	},
1495
1496	start: function(event, element){
1497		if (
1498			!this.idle ||
1499			event.rightClick ||
1500			(!this.options.handle && this.options.unDraggableTags.contains(event.target.get('tag')))
1501		) return;
1502
1503		this.idle = false;
1504		this.element = element;
1505		this.opacity = element.getStyle('opacity');
1506		this.list = element.getParent();
1507		this.clone = this.getClone(event, element);
1508
1509		this.drag = new Drag.Move(this.clone, Object.merge({
1510			
1511			droppables: this.getDroppables()
1512		}, this.options.dragOptions)).addEvents({
1513			onSnap: function(){
1514				event.stop();
1515				this.clone.setStyle('visibility', 'visible');
1516				this.element.setStyle('opacity', this.options.opacity || 0);
1517				this.fireEvent('start', [this.element, this.clone]);
1518			}.bind(this),
1519			onEnter: this.insert.bind(this),
1520			onCancel: this.end.bind(this),
1521			onComplete: this.end.bind(this)
1522		});
1523
1524		this.clone.inject(this.element, 'before');
1525		this.drag.start(event);
1526	},
1527
1528	end: function(){
1529		this.drag.detach();
1530		this.element.setStyle('opacity', this.opacity);
1531		var self = this;
1532		if (this.effect){
1533			var dim = this.element.getStyles('width', 'height'),
1534				clone = this.clone,
1535				pos = clone.computePosition(this.getDroppableCoordinates(clone));
1536
1537			var destroy = function(){
1538				this.removeEvent('cancel', destroy);
1539				clone.destroy();
1540				self.reset();
1541			};
1542
1543			this.effect.element = clone;
1544			this.effect.start({
1545				top: pos.top,
1546				left: pos.left,
1547				width: dim.width,
1548				height: dim.height,
1549				opacity: 0.25
1550			}).addEvent('cancel', destroy).chain(destroy);
1551		} else {
1552			this.clone.destroy();
1553			self.reset();
1554		}
1555
1556	},
1557
1558	reset: function(){
1559		this.idle = true;
1560		this.fireEvent('complete', this.element);
1561	},
1562
1563	serialize: function(){
1564		var params = Array.link(arguments, {
1565			modifier: Type.isFunction,
1566			index: function(obj){
1567				return obj != null;
1568			}
1569		});
1570		var serial = this.lists.map(function(list){
1571			return list.getChildren().map(params.modifier || function(element){
1572				return element.get('id');
1573			}, this);
1574		}, this);
1575
1576		var index = params.index;
1577		if (this.lists.length == 1) index = 0;
1578		return (index || index === 0) && index >= 0 && index < this.lists.length ? serial[index] : serial;
1579	}
1580
1581});
1582
1583})();
1584
1585/*
1586---
1587
1588name: Element.Event.Pseudos
1589
1590description: Adds the functionality to add pseudo events for Elements
1591
1592license: MIT-style license
1593
1594authors:
1595  - Arian Stolwijk
1596
1597requires: [Core/Element.Event, Core/Element.Delegation, Events.Pseudos]
1598
1599provides: [Element.Event.Pseudos, Element.Delegation.Pseudo]
1600
1601...
1602*/
1603
1604(function(){
1605
1606var pseudos = {relay: false},
1607	copyFromEvents = ['once', 'throttle', 'pause'],
1608	count = copyFromEvents.length;
1609
1610while (count--) pseudos[copyFromEvents[count]] = Events.lookupPseudo(copyFromEvents[count]);
1611
1612DOMEvent.definePseudo = function(key, listener){
1613	pseudos[key] = listener;
1614	return this;
1615};
1616
1617var proto = Element.prototype;
1618[Element, Window, Document].invoke('implement', Events.Pseudos(pseudos, proto.addEvent, proto.removeEvent));
1619
1620})();
1621
1622/*
1623---
1624
1625name: Element.Event.Pseudos.Keys
1626
1627description: Adds functionality fire events if certain keycombinations are pressed
1628
1629license: MIT-style license
1630
1631authors:
1632  - Arian Stolwijk
1633
1634requires: [Element.Event.Pseudos]
1635
1636provides: [Element.Event.Pseudos.Keys]
1637
1638...
1639*/
1640
1641(function(){
1642
1643var keysStoreKey = '$moo:keys-pressed',
1644	keysKeyupStoreKey = '$moo:keys-keyup';
1645
1646
1647DOMEvent.definePseudo('keys', function(split, fn, args){
1648
1649	var event = args[0],
1650		keys = [],
1651		pressed = this.retrieve(keysStoreKey, []),
1652		value = split.value;
1653
1654	if (value != '+') keys.append(value.replace('++', function(){
1655		keys.push('+'); // shift++ and shift+++a
1656		return '';
1657	}).split('+'));
1658	else keys = ['+'];
1659
1660	pressed.include(event.key);
1661
1662	if (keys.every(function(key){
1663		return pressed.contains(key);
1664	})) fn.apply(this, args);
1665
1666	this.store(keysStoreKey, pressed);
1667
1668	if (!this.retrieve(keysKeyupStoreKey)){
1669		var keyup = function(event){
1670			(function(){
1671				pressed = this.retrieve(keysStoreKey, []).erase(event.key);
1672				this.store(keysStoreKey, pressed);
1673			}).delay(0, this); // Fix for IE
1674		};
1675		this.store(keysKeyupStoreKey, keyup).addEvent('keyup', keyup);
1676	}
1677
1678});
1679
1680DOMEvent.defineKeys({
1681	'16': 'shift',
1682	'17': 'control',
1683	'18': 'alt',
1684	'20': 'capslock',
1685	'33': 'pageup',
1686	'34': 'pagedown',
1687	'35': 'end',
1688	'36': 'home',
1689	'144': 'numlock',
1690	'145': 'scrolllock',
1691	'186': ';',
1692	'187': '=',
1693	'188': ',',
1694	'190': '.',
1695	'191': '/',
1696	'192': '`',
1697	'219': '[',
1698	'220': '\\',
1699	'221': ']',
1700	'222': "'",
1701	'107': '+',
1702	'109': '-', // subtract
1703	'189': '-'  // dash
1704});
1705
1706})();
1707
1708/*
1709---
1710
1711script: String.Extras.js
1712
1713name: String.Extras
1714
1715description: Extends the String native object to include methods useful in managing various kinds of strings (query strings, urls, html, etc).
1716
1717license: MIT-style license
1718
1719authors:
1720  - Aaron Newton
1721  - Guillermo Rauch
1722  - Christopher Pitt
1723
1724requires:
1725  - Core/String
1726  - Core/Array
1727  - MooTools.More
1728
1729provides: [String.Extras]
1730
1731...
1732*/
1733
1734(function(){
1735
1736var special = {
1737		'a': /[àáâãäåăą]/g,
1738		'A': /[ÀÁÂÃÄÅĂĄ]/g,
1739		'c': /[ćčç]/g,
1740		'C': /[ĆČÇ]/g,
1741		'd': /[ďđ]/g,
1742		'D': /[ĎÐ]/g,
1743		'e': /[èéêëěę]/g,
1744		'E': /[ÈÉÊËĚĘ]/g,
1745		'g': /[ğ]/g,
1746		'G': /[Ğ]/g,
1747		'i': /[ìíîï]/g,
1748		'I': /[ÌÍÎÏ]/g,
1749		'l': /[ĺľł]/g,
1750		'L': /[ĹĽŁ]/g,
1751		'n': /[ñňń]/g,
1752		'N': /[ÑŇŃ]/g,
1753		'o': /[òóôõöøő]/g,
1754		'O': /[ÒÓÔÕÖØ]/g,
1755		'r': /[řŕ]/g,
1756		'R': /[ŘŔ]/g,
1757		's': /[ššş]/g,
1758		'S': /[ŠŞŚ]/g,
1759		't': /[ťţ]/g,
1760		'T': /[ŤŢ]/g,
1761		'u': /[ùúûůüµ]/g,
1762		'U': /[ÙÚÛŮÜ]/g,
1763		'y': /[ÿý]/g,
1764		'Y': /[ŸÝ]/g,
1765		'z': /[žźż]/g,
1766		'Z': /[ŽŹŻ]/g,
1767		'th': /[þ]/g,
1768		'TH': /[Þ]/g,
1769		'dh': /[ð]/g,
1770		'DH': /[Ð]/g,
1771		'ss': /[ß]/g,
1772		'oe': /[œ]/g,
1773		'OE': /[Œ]/g,
1774		'ae': /[æ]/g,
1775		'AE': /[Æ]/g
1776	},
1777
1778	tidy = {
1779		' ': /[\xa0\u2002\u2003\u2009]/g,
1780		'*': /[\xb7]/g,
1781		'\'': /[\u2018\u2019]/g,
1782		'"': /[\u201c\u201d]/g,
1783		'...': /[\u2026]/g,
1784		'-': /[\u2013]/g,
1785	//	'--': /[\u2014]/g,
1786		'&raquo;': /[\uFFFD]/g
1787	},
1788
1789	conversions = {
1790		ms: 1,
1791		s: 1000,
1792		m: 6e4,
1793		h: 36e5
1794	},
1795
1796	findUnits = /(\d*.?\d+)([msh]+)/;
1797
1798var walk = function(string, replacements){
1799	var result = string, key;
1800	for (key in replacements) result = result.replace(replacements[key], key);
1801	return result;
1802};
1803
1804var getRegexForTag = function(tag, contents){
1805	tag = tag || (contents ? '' : '\\w+');
1806	var regstr = contents ? '<' + tag + '(?!\\w)[^>]*>([\\s\\S]*?)<\/' + tag + '(?!\\w)>' : '<\/?' + tag + '\/?>|<' + tag + '[\\s|\/][^>]*>';
1807	return new RegExp(regstr, 'gi');
1808};
1809
1810String.implement({
1811
1812	standardize: function(){
1813		return walk(this, special);
1814	},
1815
1816	repeat: function(times){
1817		return new Array(times + 1).join(this);
1818	},
1819
1820	pad: function(length, str, direction){
1821		if (this.length >= length) return this;
1822
1823		var pad = (str == null ? ' ' : '' + str)
1824			.repeat(length - this.length)
1825			.substr(0, length - this.length);
1826
1827		if (!direction || direction == 'right') return this + pad;
1828		if (direction == 'left') return pad + this;
1829
1830		return pad.substr(0, (pad.length / 2).floor()) + this + pad.substr(0, (pad.length / 2).ceil());
1831	},
1832
1833	getTags: function(tag, contents){
1834		return this.match(getRegexForTag(tag, contents)) || [];
1835	},
1836
1837	stripTags: function(tag, contents){
1838		return this.replace(getRegexForTag(tag, contents), '');
1839	},
1840
1841	tidy: function(){
1842		return walk(this, tidy);
1843	},
1844
1845	truncate: function(max, trail, atChar){
1846		var string = this;
1847		if (trail == null && arguments.length == 1) trail = '…';
1848		if (string.length > max){
1849			string = string.substring(0, max);
1850			if (atChar){
1851				var index = string.lastIndexOf(atChar);
1852				if (index != -1) string = string.substr(0, index);
1853			}
1854			if (trail) string += trail;
1855		}
1856		return string;
1857	},
1858
1859	ms: function(){
1860		// "Borrowed" from https://gist.github.com/1503944
1861		var units = findUnits.exec(this);
1862		if (units == null) return Number(this);
1863		return Number(units[1]) * conversions[units[2]];
1864	}
1865
1866});
1867
1868})();
1869
1870/*
1871---
1872
1873script: Element.Forms.js
1874
1875name: Element.Forms
1876
1877description: Extends the Element native object to include methods useful in managing inputs.
1878
1879license: MIT-style license
1880
1881authors:
1882  - Aaron Newton
1883
1884requires:
1885  - Core/Element
1886  - String.Extras
1887  - MooTools.More
1888
1889provides: [Element.Forms]
1890
1891...
1892*/
1893
1894Element.implement({
1895
1896	tidy: function(){
1897		this.set('value', this.get('value').tidy());
1898	},
1899
1900	getTextInRange: function(start, end){
1901		return this.get('value').substring(start, end);
1902	},
1903
1904	getSelectedText: function(){
1905		if (this.setSelectionRange) return this.getTextInRange(this.getSelectionStart(), this.getSelectionEnd());
1906		return document.selection.createRange().text;
1907	},
1908
1909	getSelectedRange: function(){
1910		if (this.selectionStart != null){
1911			return {
1912				start: this.selectionStart,
1913				end: this.selectionEnd
1914			};
1915		}
1916
1917		var pos = {
1918			start: 0,
1919			end: 0
1920		};
1921		var range = this.getDocument().selection.createRange();
1922		if (!range || range.parentElement() != this) return pos;
1923		var duplicate = range.duplicate();
1924
1925		if (this.type == 'text'){
1926			pos.start = 0 - duplicate.moveStart('character', -100000);
1927			pos.end = pos.start + range.text.length;
1928		} else {
1929			var value = this.get('value');
1930			var offset = value.length;
1931			duplicate.moveToElementText(this);
1932			duplicate.setEndPoint('StartToEnd', range);
1933			if (duplicate.text.length) offset -= value.match(/[\n\r]*$/)[0].length;
1934			pos.end = offset - duplicate.text.length;
1935			duplicate.setEndPoint('StartToStart', range);
1936			pos.start = offset - duplicate.text.length;
1937		}
1938		return pos;
1939	},
1940
1941	getSelectionStart: function(){
1942		return this.getSelectedRange().start;
1943	},
1944
1945	getSelectionEnd: function(){
1946		return this.getSelectedRange().end;
1947	},
1948
1949	setCaretPosition: function(pos){
1950		if (pos == 'end') pos = this.get('value').length;
1951		this.selectRange(pos, pos);
1952		return this;
1953	},
1954
1955	getCaretPosition: function(){
1956		return this.getSelectedRange().start;
1957	},
1958
1959	selectRange: function(start, end){
1960		if (this.setSelectionRange){
1961			this.focus();
1962			this.setSelectionRange(start, end);
1963		} else {
1964			var value = this.get('value');
1965			var diff = value.substr(start, end - start).replace(/\r/g, '').length;
1966			start = value.substr(0, start).replace(/\r/g, '').length;
1967			var range = this.createTextRange();
1968			range.collapse(true);
1969			range.moveEnd('character', start + diff);
1970			range.moveStart('character', start);
1971			range.select();
1972		}
1973		return this;
1974	},
1975
1976	insertAtCursor: function(value, select){
1977		var pos = this.getSelectedRange();
1978		var text = this.get('value');
1979		this.set('value', text.substring(0, pos.start) + value + text.substring(pos.end, text.length));
1980		if (select !== false) this.selectRange(pos.start, pos.start + value.length);
1981		else this.setCaretPosition(pos.start + value.length);
1982		return this;
1983	},
1984
1985	insertAroundCursor: function(options, select){
1986		options = Object.append({
1987			before: '',
1988			defaultMiddle: '',
1989			after: ''
1990		}, options);
1991
1992		var value = this.getSelectedText() || options.defaultMiddle;
1993		var pos = this.getSelectedRange();
1994		var text = this.get('value');
1995
1996		if (pos.start == pos.end){
1997			this.set('value', text.substring(0, pos.start) + options.before + value + options.after + text.substring(pos.end, text.length));
1998			this.selectRange(pos.start + options.before.length, pos.end + options.before.length + value.length);
1999		} else {
2000			var current = text.substring(pos.start, pos.end);
2001			this.set('value', text.substring(0, pos.start) + options.before + current + options.after + text.substring(pos.end, text.length));
2002			var selStart = pos.start + options.before.length;
2003			if (select !== false) this.selectRange(selStart, selStart + current.length);
2004			else this.setCaretPosition(selStart + text.length);
2005		}
2006		return this;
2007	}
2008
2009});
2010
2011/*
2012---
2013
2014script: Element.Pin.js
2015
2016name: Element.Pin
2017
2018description: Extends the Element native object to include the pin method useful for fixed positioning for elements.
2019
2020license: MIT-style license
2021
2022authors:
2023  - Aaron Newton
2024
2025requires:
2026  - Core/Element.Event
2027  - Core/Element.Dimensions
2028  - Core/Element.Style
2029  - MooTools.More
2030
2031provides: [Element.Pin]
2032
2033...
2034*/
2035
2036(function(){
2037var supportsPositionFixed = false,
2038	supportTested = false;
2039
2040var testPositionFixed = function(){
2041	var test = new Element('div').setStyles({
2042		position: 'fixed',
2043		top: 0,
2044		right: 0
2045	}).inject(document.body);
2046	supportsPositionFixed = (test.offsetTop === 0);
2047	test.dispose();
2048	supportTested = true;
2049};
2050
2051Element.implement({
2052
2053	pin: function(enable, forceScroll){
2054		if (!supportTested) testPositionFixed();
2055		if (this.getStyle('display') == 'none') return this;
2056
2057		var pinnedPosition,
2058			scroll = window.getScroll(),
2059			parent,
2060			scrollFixer;
2061
2062		if (enable !== false){
2063			pinnedPosition = this.getPosition();
2064			if (!this.retrieve('pin:_pinned')){
2065				var currentPosition = {
2066					top: pinnedPosition.y - scroll.y,
2067					left: pinnedPosition.x - scroll.x,
2068					margin: '0px',
2069					padding: '0px'
2070				};
2071
2072				if (supportsPositionFixed && !forceScroll){
2073					this.setStyle('position', 'fixed').setStyles(currentPosition);
2074				} else {
2075
2076					parent = this.getOffsetParent();
2077					var position = this.getPosition(parent),
2078						styles = this.getStyles('left', 'top');
2079
2080					if (parent && styles.left == 'auto' || styles.top == 'auto') this.setPosition(position);
2081					if (this.getStyle('position') == 'static') this.setStyle('position', 'absolute');
2082
2083					position = {
2084						x: styles.left.toInt() - scroll.x,
2085						y: styles.top.toInt() - scroll.y
2086					};
2087
2088					scrollFixer = function(){
2089						if (!this.retrieve('pin:_pinned')) return;
2090						var scroll = window.getScroll();
2091						this.setStyles({
2092							left: position.x + scroll.x,
2093							top: position.y + scroll.y
2094						});
2095					}.bind(this);
2096
2097					this.store('pin:_scrollFixer', scrollFixer);
2098					window.addEvent('scroll', scrollFixer);
2099				}
2100				this.store('pin:_pinned', true);
2101			}
2102
2103		} else {
2104			if (!this.retrieve('pin:_pinned')) return this;
2105
2106			parent = this.getParent();
2107			var offsetParent = (parent.getComputedStyle('position') != 'static' ? parent : parent.getOffsetParent());
2108
2109			pinnedPosition = this.getPosition();
2110
2111			this.store('pin:_pinned', false);
2112			scrollFixer = this.retrieve('pin:_scrollFixer');
2113			if (!scrollFixer){
2114				this.setStyles({
2115					position: 'absolute',
2116					top: pinnedPosition.y + scroll.y,
2117					left: pinnedPosition.x + scroll.x
2118				});
2119			} else {
2120				this.store('pin:_scrollFixer', null);
2121				window.removeEvent('scroll', scrollFixer);
2122			}
2123			this.removeClass('isPinned');
2124		}
2125		return this;
2126	},
2127
2128	unpin: function(){
2129		return this.pin(false);
2130	},
2131
2132	togglePin: function(){
2133		return this.pin(!this.retrieve('pin:_pinned'));
2134	}
2135
2136});
2137
2138
2139
2140})();
2141
2142/*
2143---
2144
2145script: Element.Position.js
2146
2147name: Element.Position
2148
2149description: Extends the Element native object to include methods useful positioning elements relative to others.
2150
2151license: MIT-style license
2152
2153authors:
2154  - Aaron Newton
2155  - Jacob Thornton
2156
2157requires:
2158  - Core/Options
2159  - Core/Element.Dimensions
2160  - Element.Measure
2161
2162provides: [Element.Position]
2163
2164...
2165*/
2166
2167(function(original){
2168
2169var local = Element.Position = {
2170
2171	options: {/*
2172		edge: false,
2173		returnPos: false,
2174		minimum: {x: 0, y: 0},
2175		maximum: {x: 0, y: 0},
2176		relFixedPosition: false,
2177		ignoreMargins: false,
2178		ignoreScroll: false,
2179		allowNegative: false,*/
2180		relativeTo: document.body,
2181		position: {
2182			x: 'center', //left, center, right
2183			y: 'center' //top, center, bottom
2184		},
2185		offset: {x: 0, y: 0}
2186	},
2187
2188	getOptions: function(element, options){
2189		options = Object.merge({}, local.options, options);
2190		local.setPositionOption(options);
2191		local.setEdgeOption(options);
2192		local.setOffsetOption(element, options);
2193		local.setDimensionsOption(element, options);
2194		return options;
2195	},
2196
2197	setPositionOption: function(options){
2198		options.position = local.getCoordinateFromValue(options.position);
2199	},
2200
2201	setEdgeOption: function(options){
2202		var edgeOption = local.getCoordinateFromValue(options.edge);
2203		options.edge = edgeOption ? edgeOption :
2204			(options.position.x == 'center' && options.position.y == 'center') ? {x: 'center', y: 'center'} :
2205			{x: 'left', y: 'top'};
2206	},
2207
2208	setOffsetOption: function(element, options){
2209		var parentOffset = {x: 0, y: 0};
2210		var parentScroll = {x: 0, y: 0};
2211		var offsetParent = element.measure(function(){
2212			return document.id(this.getOffsetParent());
2213		});
2214
2215		if (!offsetParent || offsetParent == element.getDocument().body) return;
2216
2217		parentScroll = offsetParent.getScroll();
2218		parentOffset = offsetParent.measure(function(){
2219			var position = this.getPosition();
2220			if (this.getStyle('position') == 'fixed'){
2221				var scroll = window.getScroll();
2222				position.x += scroll.x;
2223				position.y += scroll.y;
2224			}
2225			return position;
2226		});
2227
2228		options.offset = {
2229			parentPositioned: offsetParent != document.id(options.relativeTo),
2230			x: options.offset.x - parentOffset.x + parentScroll.x,
2231			y: options.offset.y - parentOffset.y + parentScroll.y
2232		};
2233	},
2234
2235	setDimensionsOption: function(element, options){
2236		options.dimensions = element.getDimensions({
2237			computeSize: true,
2238			styles: ['padding', 'border', 'margin']
2239		});
2240	},
2241
2242	getPosition: function(element, options){
2243		var position = {};
2244		options = local.getOptions(element, options);
2245		var relativeTo = document.id(options.relativeTo) || document.body;
2246
2247		local.setPositionCoordinates(options, position, relativeTo);
2248		if (options.edge) local.toEdge(position, options);
2249
2250		var offset = options.offset;
2251		position.left = ((position.x >= 0 || offset.parentPositioned || options.allowNegative) ? position.x : 0).toInt();
2252		position.top = ((position.y >= 0 || offset.parentPositioned || options.allowNegative) ? position.y : 0).toInt();
2253
2254		local.toMinMax(position, options);
2255
2256		if (options.relFixedPosition || relativeTo.getStyle('position') == 'fixed') local.toRelFixedPosition(relativeTo, position);
2257		if (options.ignoreScroll) local.toIgnoreScroll(relativeTo, position);
2258		if (options.ignoreMargins) local.toIgnoreMargins(position, options);
2259
2260		position.left = Math.ceil(position.left);
2261		position.top = Math.ceil(position.top);
2262		delete position.x;
2263		delete position.y;
2264
2265		return position;
2266	},
2267
2268	setPositionCoordinates: function(options, position, relativeTo){
2269		var offsetY = options.offset.y,
2270			offsetX = options.offset.x,
2271			calc = (relativeTo == document.body) ? window.getScroll() : relativeTo.getPosition(),
2272			top = calc.y,
2273			left = calc.x,
2274			winSize = window.getSize();
2275
2276		switch (options.position.x){
2277			case 'left': position.x = left + offsetX; break;
2278			case 'right': position.x = left + offsetX + relativeTo.offsetWidth; break;
2279			default: position.x = left + ((relativeTo == document.body ? winSize.x : relativeTo.offsetWidth) / 2) + offsetX; break;
2280		}
2281
2282		switch (options.position.y){
2283			case 'top': position.y = top + offsetY; break;
2284			case 'bottom': position.y = top + offsetY + relativeTo.offsetHeight; break;
2285			default: position.y = top + ((relativeTo == document.body ? winSize.y : relativeTo.offsetHeight) / 2) + offsetY; break;
2286		}
2287	},
2288
2289	toMinMax: function(position, options){
2290		var xy = {left: 'x', top: 'y'}, value;
2291		['minimum', 'maximum'].each(function(minmax){
2292			['left', 'top'].each(function(lr){
2293				value = options[minmax] ? options[minmax][xy[lr]] : null;
2294				if (value != null && ((minmax == 'minimum') ? position[lr] < value : position[lr] > value)) position[lr] = value;
2295			});
2296		});
2297	},
2298
2299	toRelFixedPosition: function(relativeTo, position){
2300		var winScroll = window.getScroll();
2301		position.top += winScroll.y;
2302		position.left += winScroll.x;
2303	},
2304
2305	toIgnoreScroll: function(relativeTo, position){
2306		var relScroll = relativeTo.getScroll();
2307		position.top -= relScroll.y;
2308		position.left -= relScroll.x;
2309	},
2310
2311	toIgnoreMargins: function(position, options){
2312		position.left += options.edge.x == 'right'
2313			? options.dimensions['margin-right']
2314			: (options.edge.x != 'center'
2315				? -options.dimensions['margin-left']
2316				: -options.dimensions['margin-left'] + ((options.dimensions['margin-right'] + options.dimensions['margin-left']) / 2));
2317
2318		position.top += options.edge.y == 'bottom'
2319			? options.dimensions['margin-bottom']
2320			: (options.edge.y != 'center'
2321				? -options.dimensions['margin-top']
2322				: -options.dimensions['margin-top'] + ((options.dimensions['margin-bottom'] + options.dimensions['margin-top']) / 2));
2323	},
2324
2325	toEdge: function(position, options){
2326		var edgeOffset = {},
2327			dimensions = options.dimensions,
2328			edge = options.edge;
2329
2330		switch (edge.x){
2331			case 'left': edgeOffset.x = 0; break;
2332			case 'right': edgeOffset.x = -dimensions.x - dimensions.computedRight - dimensions.computedLeft; break;
2333			// center
2334			default: edgeOffset.x = -(Math.round(dimensions.totalWidth / 2)); break;
2335		}
2336
2337		switch (edge.y){
2338			case 'top': edgeOffset.y = 0; break;
2339			case 'bottom': edgeOffset.y = -dimensions.y - dimensions.computedTop - dimensions.computedBottom; break;
2340			// center
2341			default: edgeOffset.y = -(Math.round(dimensions.totalHeight / 2)); break;
2342		}
2343
2344		position.x += edgeOffset.x;
2345		position.y += edgeOffset.y;
2346	},
2347
2348	getCoordinateFromValue: function(option){
2349		if (typeOf(option) != 'string') return option;
2350		option = option.toLowerCase();
2351
2352		return {
2353			x: option.test('left') ? 'left'
2354				: (option.test('right') ? 'right' : 'center'),
2355			y: option.test(/upper|top/) ? 'top'
2356				: (option.test('bottom') ? 'bottom' : 'center')
2357		};
2358	}
2359
2360};
2361
2362Element.implement({
2363
2364	position: function(options){
2365		if (options && (options.x != null || options.y != null)){
2366			return (original ? original.apply(this, arguments) : this);
2367		}
2368		var position = this.setStyle('position', 'absolute').calculatePosition(options);
2369		return (options && options.returnPos) ? position : this.setStyles(position);
2370	},
2371
2372	calculatePosition: function(options){
2373		return local.getPosition(this, options);
2374	}
2375
2376});
2377
2378})(Element.prototype.position);
2379
2380/*
2381---
2382
2383script: Element.Shortcuts.js
2384
2385name: Element.Shortcuts
2386
2387description: Extends the Element native object to include some shortcut methods.
2388
2389license: MIT-style license
2390
2391authors:
2392  - Aaron Newton
2393
2394requires:
2395  - Core/Element.Style
2396  - MooTools.More
2397
2398provides: [Element.Shortcuts]
2399
2400...
2401*/
2402
2403Element.implement({
2404
2405	isDisplayed: function(){
2406		return this.getStyle('display') != 'none';
2407	},
2408
2409	isVisible: function(){
2410		var w = this.offsetWidth,
2411			h = this.offsetHeight;
2412		return (w == 0 && h == 0) ? false : (w > 0 && h > 0) ? true : this.style.display != 'none';
2413	},
2414
2415	toggle: function(){
2416		return this[this.isDisplayed() ? 'hide' : 'show']();
2417	},
2418
2419	hide: function(){
2420		var d;
2421		try {
2422			//IE fails here if the element is not in the dom
2423			d = this.getStyle('display');
2424		} catch (e){}
2425		if (d == 'none') return this;
2426		return this.store('element:_originalDisplay', d || '').setStyle('display', 'none');
2427	},
2428
2429	show: function(display){
2430		if (!display && this.isDisplayed()) return this;
2431		display = display || this.retrieve('element:_originalDisplay') || 'block';
2432		return this.setStyle('display', (display == 'none') ? 'block' : display);
2433	},
2434
2435	swapClass: function(remove, add){
2436		return this.removeClass(remove).addClass(add);
2437	}
2438
2439});
2440
2441Document.implement({
2442
2443	clearSelection: function(){
2444		if (window.getSelection){
2445			var selection = window.getSelection();
2446			if (selection && selection.removeAllRanges) selection.removeAllRanges();
2447		} else if (document.selection && document.selection.empty){
2448			try {
2449				//IE fails here if selected element is not in dom
2450				document.selection.empty();
2451			} catch (e){}
2452		}
2453	}
2454
2455});
2456
2457/*
2458---
2459
2460script: Elements.From.js
2461
2462name: Elements.From
2463
2464description: Returns a collection of elements from a string of html.
2465
2466license: MIT-style license
2467
2468authors:
2469  - Aaron Newton
2470
2471requires:
2472  - Core/String
2473  - Core/Element
2474  - MooTools.More
2475
2476provides: [Elements.from, Elements.From]
2477
2478...
2479*/
2480
2481Elements.from = function(text, excludeScripts){
2482	if (excludeScripts || excludeScripts == null) text = text.stripScripts();
2483
2484	var container, match = text.match(/^\s*(?:<!--.*?-->\s*)*<(t[dhr]|tbody|tfoot|thead)/i);
2485
2486	if (match){
2487		container = new Element('table');
2488		var tag = match[1].toLowerCase();
2489		if (['td', 'th', 'tr'].contains(tag)){
2490			container = new Element('tbody').inject(container);
2491			if (tag != 'tr') container = new Element('tr').inject(container);
2492		}
2493	}
2494
2495	return (container || new Element('div')).set('html', text).getChildren();
2496};
2497
2498/*
2499---
2500
2501script: IframeShim.js
2502
2503name: IframeShim
2504
2505description: Defines IframeShim, a class for obscuring select lists and flash objects in IE.
2506
2507license: MIT-style license
2508
2509authors:
2510  - Aaron Newton
2511
2512requires:
2513  - Core/Element.Event
2514  - Core/Element.Style
2515  - Core/Options
2516  - Core/Events
2517  - Element.Position
2518  - Class.Occlude
2519
2520provides: [IframeShim]
2521
2522...
2523*/
2524
2525(function(){
2526
2527var browsers = false;
2528
2529
2530var IframeShim = this.IframeShim = new Class({
2531
2532	Implements: [Options, Events, Class.Occlude],
2533
2534	options: {
2535		className: 'iframeShim',
2536		src: 'javascript:false;document.write("");',
2537		display: false,
2538		zIndex: null,
2539		margin: 0,
2540		offset: {x: 0, y: 0},
2541		browsers: browsers
2542	},
2543
2544	property: 'IframeShim',
2545
2546	initialize: function(element, options){
2547		this.element = document.id(element);
2548		if (this.occlude()) return this.occluded;
2549		this.setOptions(options);
2550		this.makeShim();
2551		return this;
2552	},
2553
2554	makeShim: function(){
2555		if (this.options.browsers){
2556			var zIndex = this.element.getStyle('zIndex').toInt();
2557
2558			if (!zIndex){
2559				zIndex = 1;
2560				var pos = this.element.getStyle('position');
2561				if (pos == 'static' || !pos) this.element.setStyle('position', 'relative');
2562				this.element.setStyle('zIndex', zIndex);
2563			}
2564			zIndex = ((this.options.zIndex != null || this.options.zIndex === 0) && zIndex > this.options.zIndex) ? this.options.zIndex : zIndex - 1;
2565			if (zIndex < 0) zIndex = 1;
2566			this.shim = new Element('iframe', {
2567				src: this.options.src,
2568				scrolling: 'no',
2569				frameborder: 0,
2570				styles: {
2571					zIndex: zIndex,
2572					position: 'absolute',
2573					border: 'none',
2574					filter: 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)'
2575				},
2576				'class': this.options.className
2577			}).store('IframeShim', this);
2578			var inject = (function(){
2579				this.shim.inject(this.element, 'after');
2580				this[this.options.display ? 'show' : 'hide']();
2581				this.fireEvent('inject');
2582			}).bind(this);
2583			if (!IframeShim.ready) window.addEvent('load', inject);
2584			else inject();
2585		} else {
2586			this.position = this.hide = this.show = this.dispose = Function.convert(this);
2587		}
2588	},
2589
2590	position: function(){
2591		if (!IframeShim.ready || !this.shim) return this;
2592		var size = this.element.measure(function(){
2593			return this.getSize();
2594		});
2595		if (this.options.margin != undefined){
2596			size.x = size.x - (this.options.margin * 2);
2597			size.y = size.y - (this.options.margin * 2);
2598			this.options.offset.x += this.options.margin;
2599			this.options.offset.y += this.options.margin;
2600		}
2601		this.shim.set({width: size.x, height: size.y}).position({
2602			relativeTo: this.element,
2603			offset: this.options.offset
2604		});
2605		return this;
2606	},
2607
2608	hide: function(){
2609		if (this.shim) this.shim.setStyle('display', 'none');
2610		return this;
2611	},
2612
2613	show: function(){
2614		if (this.shim) this.shim.setStyle('display', 'block');
2615		return this.position();
2616	},
2617
2618	dispose: function(){
2619		if (this.shim) this.shim.dispose();
2620		return this;
2621	},
2622
2623	destroy: function(){
2624		if (this.shim) this.shim.destroy();
2625		return this;
2626	}
2627
2628});
2629
2630})();
2631
2632window.addEvent('load', function(){
2633	IframeShim.ready = true;
2634});
2635
2636/*
2637---
2638
2639script: Mask.js
2640
2641name: Mask
2642
2643description: Creates a mask element to cover another.
2644
2645license: MIT-style license
2646
2647authors:
2648  - Aaron Newton
2649
2650requires:
2651  - Core/Options
2652  - Core/Events
2653  - Core/Element.Event
2654  - Class.Binds
2655  - Element.Position
2656  - IframeShim
2657
2658provides: [Mask]
2659
2660...
2661*/
2662(function(){
2663
2664var Mask = this.Mask = new Class({
2665
2666	Implements: [Options, Events],
2667
2668	Binds: ['position'],
2669
2670	options: {/*
2671		onShow: function(){},
2672		onHide: function(){},
2673		onDestroy: function(){},
2674		onClick: function(event){},
2675		inject: {
2676			where: 'after',
2677			target: null,
2678		},
2679		hideOnClick: false,
2680		id: null,
2681		destroyOnHide: false,*/
2682		style: {},
2683		'class': 'mask',
2684		maskMargins: false,
2685		useIframeShim: true,
2686		iframeShimOptions: {}
2687	},
2688
2689	initialize: function(target, options){
2690		this.target = document.id(target) || document.id(document.body);
2691		this.target.store('mask', this);
2692		this.setOptions(options);
2693		this.render();
2694		this.inject();
2695	},
2696
2697	render: function(){
2698		this.element = new Element('div', {
2699			'class': this.options['class'],
2700			id: this.options.id || 'mask-' + String.uniqueID(),
2701			styles: Object.merge({}, this.options.style, {
2702				display: 'none'
2703			}),
2704			events: {
2705				click: function(event){
2706					this.fireEvent('click', event);
2707					if (this.options.hideOnClick) this.hide();
2708				}.bind(this)
2709			}
2710		});
2711
2712		this.hidden = true;
2713	},
2714
2715	toElement: function(){
2716		return this.element;
2717	},
2718
2719	inject: function(target, where){
2720		where = where || (this.options.inject ? this.options.inject.where : '') || (this.target == document.body ? 'inside' : 'after');
2721		target = target || (this.options.inject && this.options.inject.target) || this.target;
2722
2723		this.element.inject(target, where);
2724
2725		if (this.options.useIframeShim){
2726			this.shim = new IframeShim(this.element, this.options.iframeShimOptions);
2727
2728			this.addEvents({
2729				show: this.shim.show.bind(this.shim),
2730				hide: this.shim.hide.bind(this.shim),
2731				destroy: this.shim.destroy.bind(this.shim)
2732			});
2733		}
2734	},
2735
2736	position: function(){
2737		this.resize(this.options.width, this.options.height);
2738
2739		this.element.position({
2740			relativeTo: this.target,
2741			position: 'topLeft',
2742			ignoreMargins: !this.options.maskMargins,
2743			ignoreScroll: this.target == document.body
2744		});
2745
2746		return this;
2747	},
2748
2749	resize: function(x, y){
2750		var opt = {
2751			styles: ['padding', 'border']
2752		};
2753		if (this.options.maskMargins) opt.styles.push('margin');
2754
2755		var dim = this.target.getComputedSize(opt);
2756		if (this.target == document.body){
2757			this.element.setStyles({width: 0, height: 0});
2758			var win = window.getScrollSize();
2759			if (dim.totalHeight < win.y) dim.totalHeight = win.y;
2760			if (dim.totalWidth < win.x) dim.totalWidth = win.x;
2761		}
2762		this.element.setStyles({
2763			width: Array.pick([x, dim.totalWidth, dim.x]),
2764			height: Array.pick([y, dim.totalHeight, dim.y])
2765		});
2766
2767		return this;
2768	},
2769
2770	show: function(){
2771		if (!this.hidden) return this;
2772
2773		window.addEvent('resize', this.position);
2774		this.position();
2775		this.showMask.apply(this, arguments);
2776
2777		return this;
2778	},
2779
2780	showMask: function(){
2781		this.element.setStyle('display', 'block');
2782		this.hidden = false;
2783		this.fireEvent('show');
2784	},
2785
2786	hide: function(){
2787		if (this.hidden) return this;
2788
2789		window.removeEvent('resize', this.position);
2790		this.hideMask.apply(this, arguments);
2791		if (this.options.destroyOnHide) return this.destroy();
2792
2793		return this;
2794	},
2795
2796	hideMask: function(){
2797		this.element.setStyle('display', 'none');
2798		this.hidden = true;
2799		this.fireEvent('hide');
2800	},
2801
2802	toggle: function(){
2803		this[this.hidden ? 'show' : 'hide']();
2804	},
2805
2806	destroy: function(){
2807		this.hide();
2808		this.element.destroy();
2809		this.fireEvent('destroy');
2810		this.target.eliminate('mask');
2811	}
2812
2813});
2814
2815})();
2816
2817
2818Element.Properties.mask = {
2819
2820	set: function(options){
2821		var mask = this.retrieve('mask');
2822		if (mask) mask.destroy();
2823		return this.eliminate('mask').store('mask:options', options);
2824	},
2825
2826	get: function(){
2827		var mask = this.retrieve('mask');
2828		if (!mask){
2829			mask = new Mask(this, this.retrieve('mask:options'));
2830			this.store('mask', mask);
2831		}
2832		return mask;
2833	}
2834
2835};
2836
2837Element.implement({
2838
2839	mask: function(options){
2840		if (options) this.set('mask', options);
2841		this.get('mask').show();
2842		return this;
2843	},
2844
2845	unmask: function(){
2846		this.get('mask').hide();
2847		return this;
2848	}
2849
2850});
2851
2852/*
2853---
2854
2855script: Spinner.js
2856
2857name: Spinner
2858
2859description: Adds a semi-transparent overlay over a dom element with a spinnin ajax icon.
2860
2861license: MIT-style license
2862
2863authors:
2864  - Aaron Newton
2865
2866requires:
2867  - Core/Fx.Tween
2868  - Core/Request
2869  - Class.refactor
2870  - Mask
2871
2872provides: [Spinner]
2873
2874...
2875*/
2876(function(){
2877
2878var Spinner = this.Spinner = new Class({
2879
2880	Extends: this.Mask,
2881
2882	Implements: Chain,
2883
2884	options: {/*
2885		message: false,*/
2886		'class': 'spinner',
2887		containerPosition: {},
2888		content: {
2889			'class': 'spinner-content'
2890		},
2891		messageContainer: {
2892			'class': 'spinner-msg'
2893		},
2894		img: {
2895			'class': 'spinner-img'
2896		},
2897		fxOptions: {
2898			link: 'chain'
2899		}
2900	},
2901
2902	initialize: function(target, options){
2903		this.target = document.id(target) || document.id(document.body);
2904		this.target.store('spinner', this);
2905		this.setOptions(options);
2906		this.render();
2907		this.inject();
2908
2909		// Add this to events for when noFx is true; parent methods handle hide/show.
2910		var deactivate = function(){ this.active = false; }.bind(this);
2911		this.addEvents({
2912			hide: deactivate,
2913			show: deactivate
2914		});
2915	},
2916
2917	render: function(){
2918		this.parent();
2919
2920		this.element.set('id', this.options.id || 'spinner-' + String.uniqueID());
2921
2922		this.content = document.id(this.options.content) || new Element('div', this.options.content);
2923		this.content.inject(this.element);
2924
2925		if (this.options.message){
2926			this.msg = document.id(this.options.message) || new Element('p', this.options.messageContainer).appendText(this.options.message);
2927			this.msg.inject(this.content);
2928		}
2929
2930		if (this.options.img){
2931			this.img = document.id(this.options.img) || new Element('div', this.options.img);
2932			this.img.inject(this.content);
2933		}
2934
2935		this.element.set('tween', this.options.fxOptions);
2936	},
2937
2938	show: function(noFx){
2939		if (this.active) return this.chain(this.show.bind(this));
2940		if (!this.hidden){
2941			this.callChain.delay(20, this);
2942			return this;
2943		}
2944
2945		this.target.set('aria-busy', 'true');
2946		this.active = true;
2947
2948		return this.parent(noFx);
2949	},
2950
2951	showMask: function(noFx){
2952		var pos = function(){
2953			this.content.position(Object.merge({
2954				relativeTo: this.element
2955			}, this.options.containerPosition));
2956		}.bind(this);
2957
2958		if (noFx){
2959			this.parent();
2960			pos();
2961		} else {
2962			if (!this.options.style.opacity) this.options.style.opacity = this.element.getStyle('opacity').toFloat
2962();
2963			this.element.setStyles({
2964				display: 'block',
2965				opacity: 0
2966			}).tween('opacity', this.options.style.opacity);
2967			pos();
2968			this.hidden = false;
2969			this.fireEvent('show');
2970			this.callChain();
2971		}
2972	},
2973
2974	hide: function(noFx){
2975		if (this.active) return this.chain(this.hide.bind(this));
2976		if (this.hidden){
2977			this.callChain.delay(20, this);
2978			return this;
2979		}
2980
2981		this.target.set('aria-busy', 'false');
2982		this.active = true;
2983
2984		return this.parent(noFx);
2985	},
2986
2987	hideMask: function(noFx){
2988		if (noFx) return this.parent();
2989		this.element.tween('opacity', 0).get('tween').chain(function(){
2990			this.element.setStyle('display', 'none');
2991			this.hidden = true;
2992			this.fireEvent('hide');
2993			this.callChain();
2994		}.bind(this));
2995	},
2996
2997	destroy: function(){
2998		this.content.destroy();
2999		this.parent();
3000		this.target.eliminate('spinner');
3001	}
3002
3003});
3004
3005})();
3006
3007Request = Class.refactor(Request, {
3008
3009	options: {
3010		useSpinner: false,
3011		spinnerOptions: {},
3012		spinnerTarget: false
3013	},
3014
3015	initialize: function(options){
3016		this._send = this.send;
3017		this.send = function(options){
3018			var spinner = this.getSpinner();
3019			if (spinner) spinner.chain(this._send.pass(options, this)).show();
3020			else this._send(options);
3021			return this;
3022		};
3023		this.previous(options);
3024	},
3025
3026	getSpinner: function(){
3027		if (!this.spinner){
3028			var update = document.id(this.options.spinnerTarget) || document.id(this.options.update);
3029			if (this.options.useSpinner && update){
3030				update.set('spinner', this.options.spinnerOptions);
3031				var spinner = this.spinner = update.get('spinner');
3032				['complete', 'exception', 'cancel'].each(function(event){
3033					this.addEvent(event, spinner.hide.bind(spinner));
3034				}, this);
3035			}
3036		}
3037		return this.spinner;
3038	}
3039
3040});
3041
3042Element.Properties.spinner = {
3043
3044	set: function(options){
3045		var spinner = this.retrieve('spinner');
3046		if (spinner) spinner.destroy();
3047		return this.eliminate('spinner').store('spinner:options', options);
3048	},
3049
3050	get: function(){
3051		var spinner = this.retrieve('spinner');
3052		if (!spinner){
3053			spinner = new Spinner(this, this.retrieve('spinner:options'));
3054			this.store('spinner', spinner);
3055		}
3056		return spinner;
3057	}
3058
3059};
3060
3061Element.implement({
3062
3063	spin: function(options){
3064		if (options) this.set('spinner', options);
3065		this.get('spinner').show();
3066		return this;
3067	},
3068
3069	unspin: function(){
3070		this.get('spinner').hide();
3071		return this;
3072	}
3073
3074});
3075
3076/*
3077---
3078
3079script: String.QueryString.js
3080
3081name: String.QueryString
3082
3083description: Methods for dealing with URI query strings.
3084
3085license: MIT-style license
3086
3087authors:
3088  - Sebastian Markbåge
3089  - Aaron Newton
3090  - Lennart Pilon
3091  - Valerio Proietti
3092
3093requires:
3094  - Core/Array
3095  - Core/String
3096  - MooTools.More
3097
3098provides: [String.QueryString]
3099
3100...
3101*/
3102
3103(function(){
3104
3105/**
3106 * decodeURIComponent doesn't do the correct thing with query parameter keys or
3107 * values. Specifically, it leaves '+' as '+' when it should be converting them
3108 * to spaces as that's the specification. When browsers submit HTML forms via
3109 * GET, the values are encoded using 'application/x-www-form-urlencoded'
3110 * which converts spaces to '+'.
3111 *
3112 * See: http://unixpapa.com/js/querystring.html for a description of the
3113 * problem.
3114 */
3115var decodeComponent = function(str){
3116	return decodeURIComponent(str.replace(/\+/g, ' '));
3117};
3118
3119String.implement({
3120
3121	parseQueryString: function(decodeKeys, decodeValues){
3122		if (decodeKeys == null) decodeKeys = true;
3123		if (decodeValues == null) decodeValues = true;
3124
3125		var vars = this.split(/[&;]/),
3126			object = {};
3127		if (!vars.length) return object;
3128
3129		vars.each(function(val){
3130			var index = val.indexOf('=') + 1,
3131				value = index ? val.substr(index) : '',
3132				keys = index ? val.substr(0, index - 1).match(/([^\]\[]+|(\B)(?=\]))/g) : [val],
3133				obj = object;
3134			if (!keys) return;
3135			if (decodeValues) value = decodeComponent(value);
3136			keys.each(function(key, i){
3137				if (decodeKeys) key = decodeComponent(key);
3138				var current = obj[key];
3139
3140				if (i < keys.length - 1) obj = obj[key] = current || {};
3141				else if (typeOf(current) == 'array') current.push(value);
3142				else obj[key] = current != null ? [current, value] : value;
3143			});
3144		});
3145
3146		return object;
3147	},
3148
3149	cleanQueryString: function(method){
3150		return this.split('&').filter(function(val){
3151			var index = val.indexOf('='),
3152				key = index < 0 ? '' : val.substr(0, index),
3153				value = val.substr(index + 1);
3154
3155			return method ? method.call(null, key, value) : (value || value === 0);
3156		}).join('&');
3157	}
3158
3159});
3160
3161})();
3162
3163/*
3164---
3165
3166script: Form.Request.js
3167
3168name: Form.Request
3169
3170description: Handles the basic functionality of submitting a form and updating a dom element with the result.
3171
3172license: MIT-style license
3173
3174authors:
3175  - Aaron Newton
3176
3177requires:
3178  - Core/Request.HTML
3179  - Class.Binds
3180  - Class.Occlude
3181  - Spinner
3182  - String.QueryString
3183  - Element.Delegation.Pseudo
3184
3185provides: [Form.Request]
3186
3187...
3188*/
3189
3190if (!window.Form) window.Form = {};
3191
3192(function(){
3193
3194Form.Request = new Class({
3195
3196	Binds: ['onSubmit', 'onFormValidate'],
3197
3198	Implements: [Options, Events, Class.Occlude],
3199
3200	options: {/*
3201		onFailure: function(){},
3202		onSuccess: function(){}, // aliased to onComplete,
3203		onSend: function(){}*/
3204		requestOptions: {
3205			evalScripts: true,
3206			useSpinner: true,
3207			emulation: false,
3208			link: 'ignore'
3209		},
3210		sendButtonClicked: true,
3211		extraData: {},
3212		resetForm: true
3213	},
3214
3215	property: 'form.request',
3216
3217	initialize: function(form, target, options){
3218		this.element = document.id(form);
3219		if (this.occlude()) return this.occluded;
3220		this.setOptions(options)
3221			.setTarget(target)
3222			.attach();
3223	},
3224
3225	setTarget: function(target){
3226		this.target = document.id(target);
3227		if (!this.request){
3228			this.makeRequest();
3229		} else {
3230			this.request.setOptions({
3231				update: this.target
3232			});
3233		}
3234		return this;
3235	},
3236
3237	toElement: function(){
3238		return this.element;
3239	},
3240
3241	makeRequest: function(){
3242		var self = this;
3243		this.request = new Request.HTML(Object.merge({
3244			update: this.target,
3245			emulation: false,
3246			spinnerTarget: this.element,
3247			method: this.element.get('method') || 'post'
3248		}, this.options.requestOptions)).addEvents({
3249			success: function(tree, elements, html, javascript){
3250				['complete', 'success'].each(function(evt){
3251					self.fireEvent(evt, [self.target, tree, elements, html, javascript]);
3252				});
3253			},
3254			failure: function(){
3255				self.fireEvent('complete', arguments).fireEvent('failure', arguments);
3256			},
3257			exception: function(){
3258				self.fireEvent('failure', arguments);
3259			}
3260		});
3261		return this.attachReset();
3262	},
3263
3264	attachReset: function(){
3265		if (!this.options.resetForm) return this;
3266		this.request.addEvent('success', function(){
3267			Function.attempt(function(){
3268				this.element.reset();
3269			}.bind(this));
3270			if (window.OverText) OverText.update();
3271		}.bind(this));
3272		return this;
3273	},
3274
3275	attach: function(attach){
3276		var method = (attach != false) ? 'addEvent' : 'removeEvent';
3277		this.element[method]('click:relay(button, input[type=submit])', this.saveClickedButton.bind(this));
3278
3279		var fv = this.element.retrieve('validator');
3280		if (fv) fv[method]('onFormValidate', this.onFormValidate);
3281		else this.element[method]('submit', this.onSubmit);
3282
3283		return this;
3284	},
3285
3286	detach: function(){
3287		return this.attach(false);
3288	},
3289
3290	//public method
3291	enable: function(){
3292		return this.attach();
3293	},
3294
3295	//public method
3296	disable: function(){
3297		return this.detach();
3298	},
3299
3300	onFormValidate: function(valid, form, event){
3301		//if there's no event, then this wasn't a submit event
3302		if (!event) return;
3303		var fv = this.element.retrieve('validator');
3304		if (valid || (fv && !fv.options.stopOnFailure)){
3305			event.stop();
3306			this.send();
3307		}
3308	},
3309
3310	onSubmit: function(event){
3311		var fv = this.element.retrieve('validator');
3312		if (fv){
3313			//form validator was created after Form.Request
3314			this.element.removeEvent('submit', this.onSubmit);
3315			fv.addEvent('onFormValidate', this.onFormValidate);
3316			fv.validate(event);
3317			return;
3318		}
3319		if (event) event.stop();
3320		this.send();
3321	},
3322
3323	saveClickedButton: function(event, target){
3324		var targetName = target.get('name');
3325		if (!targetName || !this.options.sendButtonClicked) return;
3326		this.options.extraData[targetName] = target.get('value') || true;
3327		this.clickedCleaner = function(){
3328			delete this.options.extraData[targetName];
3329			this.clickedCleaner = function(){};
3330		}.bind(this);
3331	},
3332
3333	clickedCleaner: function(){},
3334
3335	send: function(){
3336		var str = this.element.toQueryString().trim(),
3337			data = Object.toQueryString(this.options.extraData);
3338
3339		if (str) str += '&' + data;
3340		else str = data;
3341
3342		this.fireEvent('send', [this.element, str.parseQueryString()]);
3343		this.request.send({
3344			data: str,
3345			url: this.options.requestOptions.url || this.element.get('action')
3346		});
3347		this.clickedCleaner();
3348		return this;
3349	}
3350
3351});
3352
3353Element.implement('formUpdate', function(update, options){
3354	var fq = this.retrieve('form.request');
3355	if (!fq){
3356		fq = new Form.Request(this, update, options);
3357	} else {
3358		if (update) fq.setTarget(update);
3359		if (options) fq.setOptions(options).makeRequest();
3360	}
3361	fq.send();
3362	return this;
3363});
3364
3365})();
3366
3367/*
3368---
3369
3370script: Fx.Reveal.js
3371
3372name: Fx.Reveal
3373
3374description: Defines Fx.Reveal, a class that shows and hides elements with a transition.
3375
3376license: MIT-style license
3377
3378authors:
3379  - Aaron Newton
3380
3381requires:
3382  - Core/Fx.Morph
3383  - Element.Shortcuts
3384  - Element.Measure
3385
3386provides: [Fx.Reveal]
3387
3388...
3389*/
3390
3391(function(){
3392
3393
3394var hideTheseOf = function(object){
3395	var hideThese = object.options.hideInputs;
3396	if (window.OverText){
3397		var otClasses = [null];
3398		OverText.each(function(ot){
3399			otClasses.include('.' + ot.options.labelClass);
3400		});
3401		if (otClasses) hideThese += otClasses.join(', ');
3402	}
3403	return (hideThese) ? object.element.getElements(hideThese) : null;
3404};
3405
3406
3407Fx.Reveal = new Class({
3408
3409	Extends: Fx.Morph,
3410
3411	options: {/*
3412		onShow: function(thisElement){},
3413		onHide: function(thisElement){},
3414		onComplete: function(thisElement){},
3415		heightOverride: null,
3416		widthOverride: null,*/
3417		link: 'cancel',
3418		styles: ['padding', 'border', 'margin'],
3419		transitionOpacity: 'opacity' in document.documentElement,
3420		mode: 'vertical',
3421		display: function(){
3422			return this.element.get('tag') != 'tr' ? 'block' : 'table-row';
3423		},
3424		opacity: 1,
3425		hideInputs: !('opacity' in document.documentElement) ? 'select, input, textarea, object, embed' : null
3426	},
3427
3428	dissolve: function(){
3429		if (!this.hiding && !this.showing){
3430			if (this.element.getStyle('display') != 'none'){
3431				this.hiding = true;
3432				this.showing = false;
3433				this.hidden = true;
3434				this.cssText = this.element.style.cssText;
3435
3436				var startStyles = this.element.getComputedSize({
3437					styles: this.options.styles,
3438					mode: this.options.mode
3439				});
3440				if (this.options.transitionOpacity) startStyles.opacity = this.options.opacity;
3441
3442				var zero = {};
3443				Object.each(startStyles, function(style, name){
3444					zero[name] = [style, 0];
3445				});
3446
3447				this.element.setStyles({
3448					display: Function.convert(this.options.display).call(this),
3449					overflow: 'hidden'
3450				});
3451
3452				var hideThese = hideTheseOf(this);
3453				if (hideThese) hideThese.setStyle('visibility', 'hidden');
3454
3455				this.$chain.unshift(function(){
3456					if (this.hidden){
3457						this.hiding = false;
3458						this.element.style.cssText = this.cssText;
3459						this.element.setStyle('display', 'none');
3460						if (hideThese) hideThese.setStyle('visibility', 'visible');
3461					}
3462					this.fireEvent('hide', this.element);
3463					this.callChain();
3464				}.bind(this));
3465
3466				this.start(zero);
3467			} else {
3468				this.callChain.delay(10, this);
3469				this.fireEvent('complete', this.element);
3470				this.fireEvent('hide', this.element);
3471			}
3472		} else if (this.options.link == 'chain'){
3473			this.chain(this.dissolve.bind(this));
3474		} else if (this.options.link == 'cancel' && !this.hiding){
3475			this.cancel();
3476			this.dissolve();
3477		}
3478		return this;
3479	},
3480
3481	reveal: function(){
3482		if (!this.showing && !this.hiding){
3483			if (this.element.getStyle('display') == 'none'){
3484				this.hiding = false;
3485				this.showing = true;
3486				this.hidden = false;
3487				this.cssText = this.element.style.cssText;
3488
3489				var startStyles;
3490				this.element.measure(function(){
3491					startStyles = this.element.getComputedSize({
3492						styles: this.options.styles,
3493						mode: this.options.mode
3494					});
3495				}.bind(this));
3496				if (this.options.heightOverride != null) startStyles.height = this.options.heightOverride.toInt();
3497				if (this.options.widthOverride != null) startStyles.width = this.options.widthOverride.toInt();
3498				if (this.options.transitionOpacity){
3499					this.element.setStyle('opacity', 0);
3500					startStyles.opacity = this.options.opacity;
3501				}
3502
3503				var zero = {
3504					height: 0,
3505					display: Function.convert(this.options.display).call(this)
3506				};
3507				Object.each(startStyles, function(style, name){
3508					zero[name] = 0;
3509				});
3510				zero.overflow = 'hidden';
3511
3512				this.element.setStyles(zero);
3513
3514				var hideThese = hideTheseOf(this);
3515				if (hideThese) hideThese.setStyle('visibility', 'hidden');
3516
3517				this.$chain.unshift(function(){
3518					this.element.style.cssText = this.cssText;
3519					this.element.setStyle('display', Function.convert(this.options.display).call(this));
3520					if (!this.hidden) this.showing = false;
3521					if (hideThese) hideThese.setStyle('visibility', 'visible');
3522					this.callChain();
3523					this.fireEvent('show', this.element);
3524				}.bind(this));
3525
3526				this.start(startStyles);
3527			} else {
3528				this.callChain();
3529				this.fireEvent('complete', this.element);
3530				this.fireEvent('show', this.element);
3531			}
3532		} else if (this.options.link == 'chain'){
3533			this.chain(this.reveal.bind(this));
3534		} else if (this.options.link == 'cancel' && !this.showing){
3535			this.cancel();
3536			this.reveal();
3537		}
3538		return this;
3539	},
3540
3541	toggle: function(){
3542		if (this.element.getStyle('display') == 'none'){
3543			this.reveal();
3544		} else {
3545			this.dissolve();
3546		}
3547		return this;
3548	},
3549
3550	cancel: function(){
3551		this.parent.apply(this, arguments);
3552		if (this.cssText != null) this.element.style.cssText = this.cssText;
3553		this.hiding = false;
3554		this.showing = false;
3555		return this;
3556	}
3557
3558});
3559
3560Element.Properties.reveal = {
3561
3562	set: function(options){
3563		this.get('reveal').cancel().setOptions(options);
3564		return this;
3565	},
3566
3567	get: function(){
3568		var reveal = this.retrieve('reveal');
3569		if (!reveal){
3570			reveal = new Fx.Reveal(this);
3571			this.store('reveal', reveal);
3572		}
3573		return reveal;
3574	}
3575
3576};
3577
3578Element.Properties.dissolve = Element.Properties.reveal;
3579
3580Element.implement({
3581
3582	reveal: function(options){
3583		this.get('reveal').setOptions(options).reveal();
3584		return this;
3585	},
3586
3587	dissolve: function(options){
3588		this.get('reveal').setOptions(options).dissolve();
3589		return this;
3590	},
3591
3592	nix: function(options){
3593		var params = Array.link(arguments, {destroy: Type.isBoolean, options: Type.isObject});
3594		this.get('reveal').setOptions(options).dissolve().chain(function(){
3595			this[params.destroy ? 'destroy' : 'dispose']();
3596		}.bind(this));
3597		return this;
3598	},
3599
3600	wink: function(){
3601		var params = Array.link(arguments, {duration: Type.isNumber, options: Type.isObject});
3602		var reveal = this.get('reveal').setOptions(params.options);
3603		reveal.reveal().chain(function(){
3604			(function(){
3605				reveal.dissolve();
3606			}).delay(params.duration || 2000);
3607		});
3608	}
3609
3610});
3611
3612})();
3613
3614/*
3615---
3616
3617script: Form.Request.Append.js
3618
3619name: Form.Request.Append
3620
3621description: Handles the basic functionality of submitting a form and updating a dom element with the result. The result is appended to the DOM element instead of replacing its contents.
3622
3623license: MIT-style license
3624
3625authors:
3626  - Aaron Newton
3627
3628requires:
3629  - Form.Request
3630  - Fx.Reveal
3631  - Elements.from
3632
3633provides: [Form.Request.Append]
3634
3635...
3636*/
3637
3638Form.Request.Append = new Class({
3639
3640	Extends: Form.Request,
3641
3642	options: {
3643		//onBeforeEffect: function(){},
3644		useReveal: true,
3645		revealOptions: {},
3646		inject: 'bottom'
3647	},
3648
3649	makeRequest: function(){
3650		this.request = new Request.HTML(Object.merge({
3651			url: this.element.get('action'),
3652			method: this.element.get('method') || 'post',
3653			spinnerTarget: this.element
3654		}, this.options.requestOptions, {
3655			evalScripts: false
3656		})).addEvents({
3657			success: function(tree, elements, html, javascript){
3658				var container;
3659				var kids = Elements.from(html);
3660				if (kids.length == 1){
3661					container = kids[0];
3662				} else {
3663					container = new Element('div', {
3664						styles: {
3665							display: 'none'
3666						}
3667					}).adopt(kids);
3668				}
3669				container.inject(this.target, this.options.inject);
3670				if (this.options.requestOptions.evalScripts) Browser.exec(javascript);
3671				this.fireEvent('beforeEffect', container);
3672				var finish = function(){
3673					this.fireEvent('success', [container, this.target, tree, elements, html, javascript]);
3674				}.bind(this);
3675				if (this.options.useReveal){
3676					container.set('reveal', this.options.revealOptions).get('reveal').chain(finish);
3677					container.reveal();
3678				} else {
3679					finish();
3680				}
3681			}.bind(this),
3682			failure: function(xhr){
3683				this.fireEvent('failure', xhr);
3684			}.bind(this)
3685		});
3686		this.attachReset();
3687	}
3688
3689});
3690
3691/*
3692---
3693
3694script: Object.Extras.js
3695
3696name: Object.Extras
3697
3698description: Extra Object generics, like getFromPath which allows a path notation to child elements.
3699
3700license: MIT-style license
3701
3702authors:
3703  - Aaron Newton
3704
3705requires:
3706  - Core/Object
3707  - MooTools.More
3708
3709provides: [Object.Extras]
3710
3711...
3712*/
3713
3714(function(){
3715
3716var defined = function(value){
3717	return value != null;
3718};
3719
3720var hasOwnProperty = Object.prototype.hasOwnProperty;
3721
3722Object.extend({
3723
3724	getFromPath: function(source, parts){
3725		if (typeof parts == 'string') parts = parts.split('.');
3726		for (var i = 0, l = parts.length; i < l; i++){
3727			if (hasOwnProperty.call(source, parts[i])) source = source[parts[i]];
3728			else return null;
3729		}
3730		return source;
3731	},
3732
3733	cleanValues: function(object, method){
3734		method = method || defined;
3735		for (var key in object) if (!method(object[key])){
3736			delete object[key];
3737		}
3738		return object;
3739	},
3740
3741	erase: function(object, key){
3742		if (hasOwnProperty.call(object, key)) delete object[key];
3743		return object;
3744	},
3745
3746	run: function(object){
3747		var args = Array.slice(arguments, 1);
3748		for (var key in object) if (object[key].apply){
3749			object[key].apply(object, args);
3750		}
3751		return object;
3752	}
3753
3754});
3755
3756})();
3757
3758/*
3759---
3760
3761script: Locale.js
3762
3763name: Locale
3764
3765description: Provides methods for localization.
3766
3767license: MIT-style license
3768
3769authors:
3770  - Aaron Newton
3771  - Arian Stolwijk
3772
3773requires:
3774  - Core/Events
3775  - Object.Extras
3776  - MooTools.More
3777
3778provides: [Locale, Lang]
3779
3780...
3781*/
3782
3783(function(){
3784
3785var current = null,
3786	locales = {},
3787	inherits = {};
3788
3789var getSet = function(set){
3790	if (instanceOf(set, Locale.Set)) return set;
3791	else return locales[set];
3792};
3793
3794var Locale = this.Locale = {
3795
3796	define: function(locale, set, key, value){
3797		var name;
3798		if (instanceOf(locale, Locale.Set)){
3799			name = locale.name;
3800			if (name) locales[name] = locale;
3801		} else {
3802			name = locale;
3803			if (!locales[name]) locales[name] = new Locale.Set(name);
3804			locale = locales[name];
3805		}
3806
3807		if (set) locale.define(set, key, value);
3808
3809		
3810
3811		if (!current) current = locale;
3812
3813		return locale;
3814	},
3815
3816	use: function(locale){
3817		locale = getSet(locale);
3818
3819		if (locale){
3820			current = locale;
3821
3822			this.fireEvent('change', locale);
3823
3824			
3825		}
3826
3827		return this;
3828	},
3829
3830	getCurrent: function(){
3831		return current;
3832	},
3833
3834	get: function(key, args){
3835		return (current) ? current.get(key, args) : '';
3836	},
3837
3838	inherit: function(locale, inherits, set){
3839		locale = getSet(locale);
3840
3841		if (locale) locale.inherit(inherits, set);
3842		return this;
3843	},
3844
3845	list: function(){
3846		return Object.keys(locales);
3847	}
3848
3849};
3850
3851Object.append(Locale, new Events);
3852
3853Locale.Set = new Class({
3854
3855	sets: {},
3856
3857	inherits: {
3858		locales: [],
3859		sets: {}
3860	},
3861
3862	initialize: function(name){
3863		this.name = name || '';
3864	},
3865
3866	define: function(set, key, value){
3867		var defineData = this.sets[set];
3868		if (!defineData) defineData = {};
3869
3870		if (key){
3871			if (typeOf(key) == 'object') defineData = Object.merge(defineData, key);
3872			else defineData[key] = value;
3873		}
3874		this.sets[set] = defineData;
3875
3876		return this;
3877	},
3878
3879	get: function(key, args, _base){
3880		var value = Object.getFromPath(this.sets, key);
3881		if (value != null){
3882			var type = typeOf(value);
3883			if (type == 'function') value = value.apply(null, Array.convert(args));
3884			else if (type == 'object') value = Object.clone(value);
3885			return value;
3886		}
3887
3888		// get value of inherited locales
3889		var index = key.indexOf('.'),
3890			set = index < 0 ? key : key.substr(0, index),
3891			names = (this.inherits.sets[set] || []).combine(this.inherits.locales).include('en-US');
3892		if (!_base) _base = [];
3893
3894		for (var i = 0, l = names.length; i < l; i++){
3895			if (_base.contains(names[i])) continue;
3896			_base.include(names[i]);
3897
3898			var locale = locales[names[i]];
3899			if (!locale) continue;
3900
3901			value = locale.get(key, args, _base);
3902			if (value != null) return value;
3903		}
3904
3905		return '';
3906	},
3907
3908	inherit: function(names, set){
3909		names = Array.convert(names);
3910
3911		if (set && !this.inherits.sets[set]) this.inherits.sets[set] = [];
3912
3913		var l = names.length;
3914		while (l--) (set ? this.inherits.sets[set] : this.inherits.locales).unshift(names[l]);
3915
3916		return this;
3917	}
3918
3919});
3920
3921
3922
3923})();
3924
3925/*
3926---
3927
3928name: Locale.en-US.Date
3929
3930description: Date messages for US English.
3931
3932license: MIT-style license
3933
3934authors:
3935  - Aaron Newton
3936
3937requires:
3938  - Locale
3939
3940provides: [Locale.en-US.Date]
3941
3942...
3943*/
3944
3945Locale.define('en-US', 'Date', {
3946
3947	months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
3948	months_abbr: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
3949	days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
3950	days_abbr: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
3951
3952	// Culture's date order: MM/DD/YYYY
3953	dateOrder: ['month', 'date', 'year'],
3954	shortDate: '%m/%d/%Y',
3955	shortTime: '%I:%M%p',
3956	AM: 'AM',
3957	PM: 'PM',
3958	firstDayOfWeek: 0,
3959
3960	// Date.Extras
3961	ordinal: function(dayOfMonth){
3962		// 1st, 2nd, 3rd, etc.
3963		return (dayOfMonth > 3 && dayOfMonth < 21) ? 'th' : ['th', 'st', 'nd', 'rd', 'th'][Math.min(dayOfMonth % 10, 4)];
3964	},
3965
3966	lessThanMinuteAgo: 'less than a minute ago',
3967	minuteAgo: 'about a minute ago',
3968	minutesAgo: '{delta} minutes ago',
3969	hourAgo: 'about an hour ago',
3970	hoursAgo: 'about {delta} hours ago',
3971	dayAgo: '1 day ago',
3972	daysAgo: '{delta} days ago',
3973	weekAgo: '1 week ago',
3974	weeksAgo: '{delta} weeks ago',
3975	monthAgo: '1 month ago',
3976	monthsAgo: '{delta} months ago',
3977	yearAgo: '1 year ago',
3978	yearsAgo: '{delta} years ago',
3979
3980	lessThanMinuteUntil: 'less than a minute from now',
3981	minuteUntil: 'about a minute from now',
3982	minutesUntil: '{delta} minutes from now',
3983	hourUntil: 'about an hour from now',
3984	hoursUntil: 'about {delta} hours from now',
3985	dayUntil: '1 day from now',
3986	daysUntil: '{delta} days from now',
3987	weekUntil: '1 week from now',
3988	weeksUntil: '{delta} weeks from now',
3989	monthUntil: '1 month from now',
3990	monthsUntil: '{delta} months from now',
3991	yearUntil: '1 year from now',
3992	yearsUntil: '{delta} years from now'
3993
3994});
3995
3996/*
3997---
3998
3999script: Date.js
4000
4001name: Date
4002
4003description: Extends the Date native object to include methods useful in managing dates.
4004
4005license: MIT-style license
4006
4007authors:
4008  - Aaron Newton
4009  - Nicholas Barthelemy - https://svn.nbarthelemy.com/date-js/
4010  - Harald Kirshner - mail [at] digitarald.de; http://digitarald.de
4011  - Scott Kyle - scott [at] appden.com; http://appden.com
4012
4013requires:
4014  - Core/Array
4015  - Core/String
4016  - Core/Number
4017  - MooTools.More
4018  - Locale
4019  - Locale.en-US.Date
4020
4021provides: [Date]
4022
4023...
4024*/
4025
4026(function(){
4027
4028var Date = this.Date;
4029
4030var DateMethods = Date.Methods = {
4031	ms: 'Milliseconds',
4032	year: 'FullYear',
4033	min: 'Minutes',
4034	mo: 'Month',
4035	sec: 'Seconds',
4036	hr: 'Hours'
4037};
4038
4039[
4040	'Date', 'Day', 'FullYear', 'Hours', 'Milliseconds', 'Minutes', 'Month', 'Seconds', 'Time', 'TimezoneOffset',
4041	'Week', 'Timezone', 'GMTOffset', 'DayOfYear', 'LastMonth', 'LastDayOfMonth', 'UTCDate', 'UTCDay', 'UTCFullYear',
4042	'AMPM', 'Ordinal', 'UTCHours', 'UTCMilliseconds', 'UTCMinutes', 'UTCMonth', 'UTCSeconds', 'UTCMilliseconds'
4043].each(function(method){
4044	Date.Methods[method.toLowerCase()] = method;
4045});
4046
4047var pad = function(n, digits, string){
4048	if (digits == 1) return n;
4049	return n < Math.pow(10, digits - 1) ? (string || '0') + pad(n, digits - 1, string) : n;
4050};
4051
4052Date.implement({
4053
4054	set: function(prop, value){
4055		prop = prop.toLowerCase();
4056		var method = DateMethods[prop] && 'set' + DateMethods[prop];
4057		if (method && this[method]) this[method](value);
4058		return this;
4059	}.overloadSetter(),
4060
4061	get: function(prop){
4062		prop = prop.toLowerCase();
4063		var method = DateMethods[prop] && 'get' + DateMethods[prop];
4064		if (method && this[method]) return this[method]();
4065		return null;
4066	}.overloadGetter(),
4067
4068	clone: function(){
4069		return new Date(this.get('time'));
4070	},
4071
4072	increment: function(interval, times){
4073		interval = interval || 'day';
4074		times = times != null ? times : 1;
4075
4076		switch (interval){
4077			case 'year':
4078				return this.increment('month', times * 12);
4079			case 'month':
4080				var d = this.get('date');
4081				this.set('date', 1).set('mo', this.get('mo') + times);
4082				return this.set('date', d.min(this.get('lastdayofmonth')));
4083			case 'week':
4084				return this.increment('day', times * 7);
4085			case 'day':
4086				return this.set('date', this.get('date') + times);
4087		}
4088
4089		if (!Date.units[interval]) throw new Error(interval + ' is not a supported interval');
4090
4091		return this.set('time', this.get('time') + times * Date.units[interval]());
4092	},
4093
4094	decrement: function(interval, times){
4095		return this.increment(interval, -1 * (times != null ? times : 1));
4096	},
4097
4098	isLeapYear: function(){
4099		return Date.isLeapYear(this.get('year'));
4100	},
4101
4102	clearTime: function(){
4103		return this.set({hr: 0, min: 0, sec: 0, ms: 0});
4104	},
4105
4106	diff: function(date, resolution){
4107		if (typeOf(date) == 'string') date = Date.parse(date);
4108
4109		return ((date - this) / Date.units[resolution || 'day'](3, 3)).round(); // non-leap year, 30-day month
4110	},
4111
4112	getLastDayOfMonth: function(){
4113		return Date.daysInMonth(this.get('mo'), this.get('year'));
4114	},
4115
4116	getDayOfYear: function(){
4117		return (Date.UTC(this.get('year'), this.get('mo'), this.get('date') + 1)
4118			- Date.UTC(this.get('year'), 0, 1)) / Date.units.day();
4119	},
4120
4121	setDay: function(day, firstDayOfWeek){
4122		if (firstDayOfWeek == null){
4123			firstDayOfWeek = Date.getMsg('firstDayOfWeek');
4124			if (firstDayOfWeek === '') firstDayOfWeek = 1;
4125		}
4126
4127		day = (7 + Date.parseDay(day, true) - firstDayOfWeek) % 7;
4128		var currentDay = (7 + this.get('day') - firstDayOfWeek) % 7;
4129
4130		return this.increment('day', day - currentDay);
4131	},
4132
4133	getWeek: function(firstDayOfWeek){
4134		if (firstDayOfWeek == null){
4135			firstDayOfWeek = Date.getMsg('firstDayOfWeek');
4136			if (firstDayOfWeek === '') firstDayOfWeek = 1;
4137		}
4138
4139		var date = this,
4140			dayOfWeek = (7 + date.get('day') - firstDayOfWeek) % 7,
4141			dividend = 0,
4142			firstDayOfYear;
4143
4144		if (firstDayOfWeek == 1){
4145			// ISO-8601, week belongs to year that has the most days of the week (i.e. has the thursday of the week)
4146			var month = date.get('month'),
4147				startOfWeek = date.get('date') - dayOfWeek;
4148
4149			if (month == 11 && startOfWeek > 28) return 1; // Week 1 of next year
4150
4151			if (month == 0 && startOfWeek < -2){
4152				// Use a date from last year to determine the week
4153				date = new Date(date).decrement('day', dayOfWeek);
4154				dayOfWeek = 0;
4155			}
4156
4157			firstDayOfYear = new Date(date.get('year'), 0, 1).get('day') || 7;
4158			if (firstDayOfYear > 4) dividend = -7; // First week of the year is not week 1
4159		} else {
4160			// In other cultures the first week of the year is always week 1 and the last week always 53 or 54.
4161			// Days in the same week can have a different weeknumber if the week spreads across two years.
4162			firstDayOfYear = new Date(date.get('year'), 0, 1).get('day');
4163		}
4164
4165		dividend += date.get('dayofyear');
4166		dividend += 6 - dayOfWeek; // Add days so we calculate the current date's week as a full week
4167		dividend += (7 + firstDayOfYear - firstDayOfWeek) % 7; // Make up for first week of the year not being a full week
4168
4169		return (dividend / 7);
4170	},
4171
4172	getOrdinal: function(day){
4173		return Date.getMsg('ordinal', day || this.get('date'));
4174	},
4175
4176	getTimezone: function(){
4177		return this.toString()
4178			.replace(/^.*? ([A-Z]{3}).[0-9]{4}.*$/, '$1')
4179			.replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, '$1$2$3');
4180	},
4181
4182	getGMTOffset: function(){
4183		var off = this.get('timezoneOffset');
4184		return ((off > 0) ? '-' : '+') + pad((off.abs() / 60).floor(), 2) + pad(off % 60, 2);
4185	},
4186
4187	setAMPM: function(ampm){
4188		ampm = ampm.toUpperCase();
4189		var hr = this.get('hr');
4190		if (hr >
4190 11 && ampm == 'AM') return this.decrement('hour', 12);
4191		else if (hr < 12 && ampm == 'PM') return this.increment('hour', 12);
4192		return this;
4193	},
4194
4195	getAMPM: function(){
4196		return (this.get('hr') < 12) ? 'AM' : 'PM';
4197	},
4198
4199	parse: function(str){
4200		this.set('time', Date.parse(str));
4201		return this;
4202	},
4203
4204	isValid: function(date){
4205		if (!date) date = this;
4206		return typeOf(date) == 'date' && !isNaN(date.valueOf());
4207	},
4208
4209	format: function(format){
4210		if (!this.isValid()) return 'invalid date';
4211
4212		if (!format) format = '%x %X';
4213		if (typeof format == 'string') format = formats[format.toLowerCase()] || format;
4214		if (typeof format == 'function') return format(this);
4215
4216		var d = this;
4217		return format.replace(/%([a-z%])/gi,
4218			function($0, $1){
4219				switch ($1){
4220					case 'a': return Date.getMsg('days_abbr')[d.get('day')];
4221					case 'A': return Date.getMsg('days')[d.get('day')];
4222					case 'b': return Date.getMsg('months_abbr')[d.get('month')];
4223					case 'B': return Date.getMsg('months')[d.get('month')];
4224					case 'c': return d.format('%a %b %d %H:%M:%S %Y');
4225					case 'd': return pad(d.get('date'), 2);
4226					case 'e': return pad(d.get('date'), 2, ' ');
4227					case 'H': return pad(d.get('hr'), 2);
4228					case 'I': return pad((d.get('hr') % 12) || 12, 2);
4229					case 'j': return pad(d.get('dayofyear'), 3);
4230					case 'k': return pad(d.get('hr'), 2, ' ');
4231					case 'l': return pad((d.get('hr') % 12) || 12, 2, ' ');
4232					case 'L': return pad(d.get('ms'), 3);
4233					case 'm': return pad((d.get('mo') + 1), 2);
4234					case 'M': return pad(d.get('min'), 2);
4235					case 'o': return d.get('ordinal');
4236					case 'p': return Date.getMsg(d.get('ampm'));
4237					case 's': return Math.round(d / 1000);
4238					case 'S': return pad(d.get('seconds'), 2);
4239					case 'T': return d.format('%H:%M:%S');
4240					case 'U': return pad(d.get('week'), 2);
4241					case 'w': return d.get('day');
4242					case 'x': return d.format(Date.getMsg('shortDate'));
4243					case 'X': return d.format(Date.getMsg('shortTime'));
4244					case 'y': return d.get('year').toString().substr(2);
4245					case 'Y': return d.get('year');
4246					case 'z': return d.get('GMTOffset');
4247					case 'Z': return d.get('Timezone');
4248				}
4249				return $1;
4250			}
4251		);
4252	},
4253
4254	toISOString: function(){
4255		return this.format('iso8601');
4256	}
4257
4258}).alias({
4259	toJSON: 'toISOString',
4260	compare: 'diff',
4261	strftime: 'format'
4262});
4263
4264// The day and month abbreviations are standardized, so we cannot use simply %a and %b because they will get localized
4265var rfcDayAbbr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
4266	rfcMonthAbbr = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
4267
4268var formats = {
4269	db: '%Y-%m-%d %H:%M:%S',
4270	compact: '%Y%m%dT%H%M%S',
4271	'short': '%d %b %H:%M',
4272	'long': '%B %d, %Y %H:%M',
4273	rfc822: function(date){
4274		return rfcDayAbbr[date.get('day')] + date.format(', %d ') + rfcMonthAbbr[date.get('month')] + date.format(' %Y %H:%M:%S %Z');
4275	},
4276	rfc2822: function(date){
4277		return rfcDayAbbr[date.get('day')] + date.format(', %d ') + rfcMonthAbbr[date.get('month')] + date.format(' %Y %H:%M:%S %z');
4278	},
4279	iso8601: function(date){
4280		return (
4281			date.getUTCFullYear() + '-' +
4282			pad(date.getUTCMonth() + 1, 2) + '-' +
4283			pad(date.getUTCDate(), 2) + 'T' +
4284			pad(date.getUTCHours(), 2) + ':' +
4285			pad(date.getUTCMinutes(), 2) + ':' +
4286			pad(date.getUTCSeconds(), 2) + '.' +
4287			pad(date.getUTCMilliseconds(), 3) + 'Z'
4288		);
4289	}
4290};
4291
4292var parsePatterns = [],
4293	nativeParse = Date.parse;
4294
4295var parseWord = function(type, word, num){
4296	var ret = -1,
4297		translated = Date.getMsg(type + 's');
4298	switch (typeOf(word)){
4299		case 'object':
4300			ret = translated[word.get(type)];
4301			break;
4302		case 'number':
4303			ret = translated[word];
4304			if (!ret) throw new Error('Invalid ' + type + ' index: ' + word);
4305			break;
4306		case 'string':
4307			var match = translated.filter(function(name){
4308				return this.test(name);
4309			}, new RegExp('^' + word, 'i'));
4310			if (!match.length) throw new Error('Invalid ' + type + ' string');
4311			if (match.length > 1) throw new Error('Ambiguous ' + type);
4312			ret = match[0];
4313	}
4314
4315	return (num) ? translated.indexOf(ret) : ret;
4316};
4317
4318var startCentury = 1900,
4319	startYear = 70;
4320
4321Date.extend({
4322
4323	getMsg: function(key, args){
4324		return Locale.get('Date.' + key, args);
4325	},
4326
4327	units: {
4328		ms: Function.convert(1),
4329		second: Function.convert(1000),
4330		minute: Function.convert(60000),
4331		hour: Function.convert(3600000),
4332		day: Function.convert(86400000),
4333		week: Function.convert(608400000),
4334		month: function(month, year){
4335			var d = new Date;
4336			return Date.daysInMonth(month != null ? month : d.get('mo'), year != null ? year : d.get('year')) * 86400000;
4337		},
4338		year: function(year){
4339			year = year || new Date().get('year');
4340			return Date.isLeapYear(year) ? 31622400000 : 31536000000;
4341		}
4342	},
4343
4344	daysInMonth: function(month, year){
4345		return [31, Date.isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
4346	},
4347
4348	isLeapYear: function(year){
4349		return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
4350	},
4351
4352	parse: function(from){
4353		var t = typeOf(from);
4354		if (t == 'number') return new Date(from);
4355		if (t != 'string') return from;
4356		from = from.clean();
4357		if (!from.length) return null;
4358
4359		var parsed;
4360		parsePatterns.some(function(pattern){
4361			var bits = pattern.re.exec(from);
4362			return (bits) ? (parsed = pattern.handler(bits)) : false;
4363		});
4364
4365		if (!(parsed && parsed.isValid())){
4366			parsed = new Date(nativeParse(from));
4367			if (!(parsed && parsed.isValid())) parsed = new Date(from.toInt());
4368		}
4369		return parsed;
4370	},
4371
4372	parseDay: function(day, num){
4373		return parseWord('day', day, num);
4374	},
4375
4376	parseMonth: function(month, num){
4377		return parseWord('month', month, num);
4378	},
4379
4380	parseUTC: function(value){
4381		var localDate = new Date(value);
4382		var utcSeconds = Date.UTC(
4383			localDate.get('year'),
4384			localDate.get('mo'),
4385			localDate.get('date'),
4386			localDate.get('hr'),
4387			localDate.get('min'),
4388			localDate.get('sec'),
4389			localDate.get('ms')
4390		);
4391		return new Date(utcSeconds);
4392	},
4393
4394	orderIndex: function(unit){
4395		return Date.getMsg('dateOrder').indexOf(unit) + 1;
4396	},
4397
4398	defineFormat: function(name, format){
4399		formats[name] = format;
4400		return this;
4401	},
4402
4403	
4404
4405	defineParser: function(pattern){
4406		parsePatterns.push((pattern.re && pattern.handler) ? pattern : build(pattern));
4407		return this;
4408	},
4409
4410	defineParsers: function(){
4411		Array.flatten(arguments).each(Date.defineParser);
4412		return this;
4413	},
4414
4415	define2DigitYearStart: function(year){
4416		startYear = year % 100;
4417		startCentury = year - startYear;
4418		return this;
4419	}
4420
4421}).extend({
4422	defineFormats: Date.defineFormat.overloadSetter()
4423});
4424
4425var regexOf = function(type){
4426	return new RegExp('(?:' + Date.getMsg(type).map(function(name){
4427		return name.substr(0, 3);
4428	}).join('|') + ')[a-z]*');
4429};
4430
4431var replacers = function(key){
4432	switch (key){
4433		case 'T':
4434			return '%H:%M:%S';
4435		case 'x': // iso8601 covers yyyy-mm-dd, so just check if month is first
4436			return ((Date.orderIndex('month') == 1) ? '%m[-./]%d' : '%d[-./]%m') + '([-./]%y)?';
4437		case 'X':
4438			return '%H([.:]%M)?([.:]%S([.:]%s)?)? ?%p? ?%z?';
4439	}
4440	return null;
4441};
4442
4443var keys = {
4444	d: /[0-2]?[0-9]|3[01]/,
4445	H: /[01]?[0-9]|2[0-3]/,
4446	I: /0?[1-9]|1[0-2]/,
4447	M: /[0-5]?\d/,
4448	s: /\d+/,
4449	o: /[a-z]*/,
4450	p: /[ap]\.?m\.?/,
4451	y: /\d{2}|\d{4}/,
4452	Y: /\d{4}/,
4453	z: /Z|[+-]\d{2}(?::?\d{2})?/
4454};
4455
4456keys.m = keys.I;
4457keys.S = keys.M;
4458
4459var currentLanguage;
4460
4461var recompile = function(language){
4462	currentLanguage = language;
4463
4464	keys.a = keys.A = regexOf('days');
4465	keys.b = keys.B = regexOf('months');
4466
4467	parsePatterns.each(function(pattern, i){
4468		if (pattern.format) parsePatterns[i] = build(pattern.format);
4469	});
4470};
4471
4472var build = function(format){
4473	if (!currentLanguage) return {format: format};
4474
4475	var parsed = [];
4476	var re = (format.source || format) // allow format to be regex
4477	.replace(/%([a-z])/gi,
4478		function($0, $1){
4479			return replacers($1) || $0;
4480		}
4481	).replace(/\((?!\?)/g, '(?:') // make all groups non-capturing
4482	.replace(/ (?!\?|\*)/g, ',? ') // be forgiving with spaces and commas
4483	.replace(/%([a-z%])/gi,
4484		function($0, $1){
4485			var p = keys[$1];
4486			if (!p) return $1;
4487			parsed.push($1);
4488			return '(' + p.source + ')';
4489		}
4490	).replace(/\[a-z\]/gi, '[a-z\\u00c0-\\uffff;\&]'); // handle unicode words
4491
4492	return {
4493		format: format,
4494		re: new RegExp('^' + re + '$', 'i'),
4495		handler: function(bits){
4496			bits = bits.slice(1).associate(parsed);
4497			var date = new Date().clearTime(),
4498				year = bits.y || bits.Y;
4499
4500			if (year != null) handle.call(date, 'y', year); // need to start in the right year
4501			if ('d' in bits) handle.call(date, 'd', 1);
4502			if ('m' in bits || bits.b || bits.B) handle.call(date, 'm', 1);
4503
4504			for (var key in bits) handle.call(date, key, bits[key]);
4505			return date;
4506		}
4507	};
4508};
4509
4510var handle = function(key, value){
4511	if (!value) return this;
4512
4513	switch (key){
4514		case 'a': case 'A': return this.set('day', Date.parseDay(value, true));
4515		case 'b': case 'B': return this.set('mo', Date.parseMonth(value, true));
4516		case 'd': return this.set('date', value);
4517		case 'H': case 'I': return this.set('hr', value);
4518		case 'm': return this.set('mo', value - 1);
4519		case 'M': return this.set('min', value);
4520		case 'p': return this.set('ampm', value.replace(/\./g, ''));
4521		case 'S': return this.set('sec', value);
4522		case 's': return this.set('ms', ('0.' + value) * 1000);
4523		case 'w': return this.set('day', value);
4524		case 'Y': return this.set('year', value);
4525		case 'y':
4526			value = +value;
4527			if (value < 100) value += startCentury + (value < startYear ? 100 : 0);
4528			return this.set('year', value);
4529		case 'z':
4530			if (value == 'Z') value = '+00';
4531			var offset = value.match(/([+-])(\d{2}):?(\d{2})?/);
4532			offset = (offset[1] + '1') * (offset[2] * 60 + (+offset[3] || 0)) + this.getTimezoneOffset();
4533			return this.set('time', this - offset * 60000);
4534	}
4535
4536	return this;
4537};
4538
4539Date.defineParsers(
4540	'%Y([-./]%m([-./]%d((T| )%X)?)?)?', // "1999-12-31", "1999-12-31 11:59pm", "1999-12-31 23:59:59", ISO8601
4541	'%Y%m%d(T%H(%M%S?)?)?', // "19991231", "19991231T1159", compact
4542	'%x( %X)?', // "12/31", "12.31.99", "12-31-1999", "12/31/2008 11:59 PM"
4543	'%d%o( %b( %Y)?)?( %X)?', // "31st", "31st December", "31 Dec 1999", "31 Dec 1999 11:59pm"
4544	'%b( %d%o)?( %Y)?( %X)?', // Same as above with month and day switched
4545	'%Y %b( %d%o( %X)?)?', // Same as above with year coming first
4546	'%o %b %d %X %z %Y', // "Thu Oct 22 08:11:23 +0000 2009"
4547	'%T', // %H:%M:%S
4548	'%H:%M( ?%p)?' // "11:05pm", "11:05 am" and "11:05"
4549);
4550
4551Locale.addEvent('change', function(language){
4552	if (Locale.get('Date')) recompile(language);
4553}).fireEvent('change', Locale.getCurrent());
4554
4555})();
4556
4557/*
4558---
4559
4560name: Locale.en-US.Form.Validator
4561
4562description: Form Validator messages for English.
4563
4564license: MIT-style license
4565
4566authors:
4567  - Aaron Newton
4568
4569requires:
4570  - Locale
4571
4572provides: [Locale.en-US.Form.Validator]
4573
4574...
4575*/
4576
4577Locale.define('en-US', 'FormValidator', {
4578
4579	required: 'This field is required.',
4580	length: 'Please enter {length} characters (you entered {elLength} characters)',
4581	minLength: 'Please enter at least {minLength} characters (you entered {length} characters).',
4582	maxLength: 'Please enter no more than {maxLength} characters (you entered {length} characters).',
4583	integer: 'Please enter an integer in this field. Numbers with decimals (e.g. 1.25) are not permitted.',
4584	numeric: 'Please enter only numeric values in this field (i.e. "1" or "1.1" or "-1" or "-1.1").',
4585	digits: 'Please use numbers and punctuation only in this field (for example, a phone number with dashes or dots is permitted).',
4586	alpha: 'Please use only letters (a-z) within this field. No spaces or other characters are allowed.',
4587	alphanum: 'Please use only letters (a-z) or numbers (0-9) in this field. No spaces or other characters are allowed.',
4588	dateSuchAs: 'Please enter a valid date such as {date}',
4589	dateInFormatMDY: 'Please enter a valid date such as MM/DD/YYYY (i.e. "12/31/1999")',
4590	email: 'Please enter a valid email address. For example "[email protected]".',
4591	url: 'Please enter a valid URL such as http://www.example.com.',
4592	currencyDollar: 'Please enter a valid $ amount. For example $100.00 .',
4593	oneRequired: 'Please enter something for at least one of these inputs.',
4594	errorPrefix: 'Error: ',
4595	warningPrefix: 'Warning: ',
4596
4597	// Form.Validator.Extras
4598	noSpace: 'There can be no spaces in this input.',
4599	reqChkByNode: 'No items are selected.',
4600	requiredChk: 'This field is required.',
4601	reqChkByName: 'Please select a {label}.',
4602	match: 'This field needs to match the {matchName} field',
4603	startDate: 'the start date',
4604	endDate: 'the end date',
4605	currentDate: 'the current date',
4606	afterDate: 'The date should be the same or after {label}.',
4607	beforeDate: 'The date should be the same or before {label}.',
4608	startMonth: 'Please select a start month',
4609	sameMonth: 'These two dates must be in the same month - you must change one or the other.',
4610	creditcard: 'The credit card number entered is invalid. Please check the number and try again. {length} digits entered.'
4611
4612});
4613
4614/*
4615---
4616
4617script: Form.Validator.js
4618
4619name: Form.Validator
4620
4621description: A css-class based form validation system.
4622
4623license: MIT-style license
4624
4625authors:
4626  - Aaron Newton
4627
4628requires:
4629  - Core/Options
4630  - Core/Events
4631  - Core/Element.Delegation
4632  - Core/Slick.Finder
4633  - Core/Element.Event
4634  - Core/Element.Style
4635  - Core/JSON
4636  - Locale
4637  - Class.Binds
4638  - Date
4639  - Element.Forms
4640  - Locale.en-US.Form.Validator
4641  - Element.Shortcuts
4642
4643provides: [Form.Validator, InputValidator, FormValidator.BaseValidators]
4644
4645...
4646*/
4647if (!window.Form) window.Form = {};
4648
4649var InputValidator = this.InputValidator = new Class({
4650
4651	Implements: [Options],
4652
4653	options: {
4654		errorMsg: 'Validation failed.',
4655		test: Function.convert(true)
4656	},
4657
4658	initialize: function(className, options){
4659		this.setOptions(options);
4660		this.className = className;
4661	},
4662
4663	test: function(field, props){
4664		field = document.id(field);
4665		return (field) ? this.options.test(field, props || this.getProps(field)) : false;
4666	},
4667
4668	getError: function(field, props){
4669		field = document.id(field);
4670		var err = this.options.errorMsg;
4671		if (typeOf(err) == 'function') err = err(field, props || this.getProps(field));
4672		return err;
4673	},
4674
4675	getProps: function(field){
4676		field = document.id(field);
4677		return (field) ? field.get('validatorProps') : {};
4678	}
4679
4680});
4681
4682Element.Properties.validators = {
4683
4684	get: function(){
4685		return (this.get('data-validators') || this.className).clean().replace(/'(\\.|[^'])*'|"(\\.|[^"])*"/g, function(match){
4686			return match.replace(' ', '\\x20');
4687		}).split(' ');
4688	}
4689
4690};
4691
4692Element.Properties.validatorProps = {
4693
4694	set: function(props){
4695		return this.eliminate('$moo:validatorProps').store('$moo:validatorProps', props);
4696	},
4697
4698	get: function(props){
4699		if (props) this.set(props);
4700		if (this.retrieve('$moo:validatorProps')) return this.retrieve('$moo:validatorProps');
4701		if (this.getProperty('data-validator-properties') || this.getProperty('val
4701idatorProps')){
4702			try {
4703				this.store('$moo:validatorProps', JSON.decode(this.getProperty('validatorProps') || this.getProperty('data-validator-properties'), false));
4704			} catch (e){
4705				return {};
4706			}
4707		} else {
4708			var vals = this.get('validators').filter(function(cls){
4709				return cls.test(':');
4710			});
4711			if (!vals.length){
4712				this.store('$moo:validatorProps', {});
4713			} else {
4714				props = {};
4715				vals.each(function(cls){
4716					var split = cls.split(':');
4717					if (split[1]){
4718						try {
4719							props[split[0]] = JSON.decode(split[1], false);
4720						} catch (e){}
4721					}
4722				});
4723				this.store('$moo:validatorProps', props);
4724			}
4725		}
4726		return this.retrieve('$moo:validatorProps');
4727	}
4728
4729};
4730
4731Form.Validator = new Class({
4732
4733	Implements: [Options, Events],
4734
4735	options: {/*
4736		onFormValidate: function(isValid, form, event){},
4737		onElementValidate: function(isValid, field, className, warn){},
4738		onElementPass: function(field){},
4739		onElementFail: function(field, validatorsFailed){}, */
4740		fieldSelectors: 'input, select, textarea',
4741		ignoreHidden: true,
4742		ignoreDisabled: true,
4743		useTitles: false,
4744		evaluateOnSubmit: true,
4745		evaluateFieldsOnBlur: true,
4746		evaluateFieldsOnChange: true,
4747		serial: true,
4748		stopOnFailure: true,
4749		warningPrefix: function(){
4750			return Form.Validator.getMsg('warningPrefix') || 'Warning: ';
4751		},
4752		errorPrefix: function(){
4753			return Form.Validator.getMsg('errorPrefix') || 'Error: ';
4754		}
4755	},
4756
4757	initialize: function(form, options){
4758		this.setOptions(options);
4759		this.element = document.id(form);
4760		this.warningPrefix = Function.convert(this.options.warningPrefix)();
4761		this.errorPrefix = Function.convert(this.options.errorPrefix)();
4762		this._bound = {
4763			onSubmit: this.onSubmit.bind(this),
4764			blurOrChange: function(event, field){
4765				this.validationMonitor(field, true);
4766			}.bind(this)
4767		};
4768		this.enable();
4769	},
4770
4771	toElement: function(){
4772		return this.element;
4773	},
4774
4775	getFields: function(){
4776		return (this.fields = this.element.getElements(this.options.fieldSelectors));
4777	},
4778
4779	enable: function(){
4780		this.element.store('validator', this);
4781		if (this.options.evaluateOnSubmit) this.element.addEvent('submit', this._bound.onSubmit);
4782		if (this.options.evaluateFieldsOnBlur){
4783			this.element.addEvent('blur:relay(input,select,textarea)', this._bound.blurOrChange);
4784		}
4785		if (this.options.evaluateFieldsOnChange){
4786			this.element.addEvent('change:relay(input,select,textarea)', this._bound.blurOrChange);
4787		}
4788	},
4789
4790	disable: function(){
4791		this.element.eliminate('validator');
4792		this.element.removeEvents({
4793			submit: this._bound.onSubmit,
4794			'blur:relay(input,select,textarea)': this._bound.blurOrChange,
4795			'change:relay(input,select,textarea)': this._bound.blurOrChange
4796		});
4797	},
4798
4799	validationMonitor: function(){
4800		clearTimeout(this.timer);
4801		this.timer = this.validateField.delay(50, this, arguments);
4802	},
4803
4804	onSubmit: function(event){
4805		if (this.validate(event)) this.reset();
4806	},
4807
4808	reset: function(){
4809		this.getFields().each(this.resetField, this);
4810		return this;
4811	},
4812
4813	validate: function(event){
4814		var result = this.getFields().map(function(field){
4815			return this.validateField(field, true);
4816		}, this).every(function(v){
4817			return v;
4818		});
4819		this.fireEvent('formValidate', [result, this.element, event]);
4820		if (this.options.stopOnFailure && !result && event) event.preventDefault();
4821		return result;
4822	},
4823
4824	validateField: function(field, force){
4825		if (this.paused) return true;
4826		field = document.id(field);
4827		var passed = !field.hasClass('validation-failed');
4828		var failed, warned;
4829		if (this.options.serial && !force){
4830			failed = this.element.getElement('.validation-failed');
4831			warned = this.element.getElement('.warning');
4832		}
4833		if (field && (!failed || force || field.hasClass('validation-failed') || (failed && !this.options.serial))){
4834			var validationTypes = field.get('validators');
4835			var validators = validationTypes.some(function(cn){
4836				return this.getValidator(cn);
4837			}, this);
4838			var validatorsFailed = [];
4839			validationTypes.each(function(className){
4840				if (className && !this.test(className, field)) validatorsFailed.include(className);
4841			}, this);
4842			passed = validatorsFailed.length === 0;
4843			if (validators && !this.hasValidator(field, 'warnOnly')){
4844				if (passed){
4845					field.addClass('validation-passed').removeClass('validation-failed');
4846					this.fireEvent('elementPass', [field]);
4847				} else {
4848					field.addClass('validation-failed').removeClass('validation-passed');
4849					this.fireEvent('elementFail', [field, validatorsFailed]);
4850				}
4851			}
4852			if (!warned){
4853				var warnings = validationTypes.some(function(cn){
4854					if (cn.test('^warn'))
4855						return this.getValidator(cn.replace(/^warn-/,''));
4856					else return null;
4857				}, this);
4858				field.removeClass('warning');
4859				var warnResult = validationTypes.map(function(cn){
4860					if (cn.test('^warn'))
4861						return this.test(cn.replace(/^warn-/,''), field, true);
4862					else return null;
4863				}, this);
4864			}
4865		}
4866		return passed;
4867	},
4868
4869	test: function(className, field, warn){
4870		field = document.id(field);
4871		if ((this.options.ignoreHidden && !field.isVisible()) || (this.options.ignoreDisabled && field.get('disabled'))) return true;
4872		var validator = this.getValidator(className);
4873		if (warn != null) warn = false;
4874		if (this.hasValidator(field, 'warnOnly')) warn = true;
4875		var isValid = field.hasClass('ignoreValidation') || (validator ? validator.test(field) : true);
4876		if (validator) this.fireEvent('elementValidate', [isValid, field, className, warn]);
4877		if (warn) return true;
4878		return isValid;
4879	},
4880
4881	hasValidator: function(field, value){
4882		return field.get('validators').contains(value);
4883	},
4884
4885	resetField: function(field){
4886		field = document.id(field);
4887		if (field){
4888			field.get('validators').each(function(className){
4889				if (className.test('^warn-')) className = className.replace(/^warn-/, '');
4890				field.removeClass('validation-failed');
4891				field.removeClass('warning');
4892				field.removeClass('validation-passed');
4893			}, this);
4894		}
4895		return this;
4896	},
4897
4898	stop: function(){
4899		this.paused = true;
4900		return this;
4901	},
4902
4903	start: function(){
4904		this.paused = false;
4905		return this;
4906	},
4907
4908	ignoreField: function(field, warn){
4909		field = document.id(field);
4910		if (field){
4911			this.enforceField(field);
4912			if (warn) field.addClass('warnOnly');
4913			else field.addClass('ignoreValidation');
4914		}
4915		return this;
4916	},
4917
4918	enforceField: function(field){
4919		field = document.id(field);
4920		if (field) field.removeClass('warnOnly').removeClass('ignoreValidation');
4921		return this;
4922	}
4923
4924});
4925
4926Form.Validator.getMsg = function(key){
4927	return Locale.get('FormValidator.' + key);
4928};
4929
4930Form.Validator.adders = {
4931
4932	validators:{},
4933
4934	add : function(className, options){
4935		this.validators[className] = new InputValidator(className, options);
4936		//if this is a class (this method is used by instances of Form.Validator and the Form.Validator namespace)
4937		//extend these validators into it
4938		//this allows validators to be global and/or per instance
4939		if (!this.initialize){
4940			this.implement({
4941				validators: this.validators
4942			});
4943		}
4944	},
4945
4946	addAllThese : function(validators){
4947		Array.convert(validators).each(function(validator){
4948			this.add(validator[0], validator[1]);
4949		}, this);
4950	},
4951
4952	getValidator: function(className){
4953		return this.validators[className.split(':')[0]];
4954	}
4955
4956};
4957
4958Object.append(Form.Validator, Form.Validator.adders);
4959
4960Form.Validator.implement(Form.Validator.adders);
4961
4962Form.Validator.add('IsEmpty', {
4963
4964	errorMsg: false,
4965	test: function(element){
4966		if (element.type == 'select-one' || element.type == 'select')
4967			return !(element.selectedIndex >= 0 && element.options[element.selectedIndex].value != '');
4968		else
4969			return ((element.get('value') == null) || (element.get('value').length == 0));
4970	}
4971
4972});
4973
4974Form.Validator.addAllThese([
4975
4976	['required', {
4977		errorMsg: function(){
4978			return Form.Validator.getMsg('required');
4979		},
4980		test: function(element){
4981			return !Form.Validator.getValidator('IsEmpty').test(element);
4982		}
4983	}],
4984
4985	['length', {
4986		errorMsg: function(element, props){
4987			if (typeOf(props.length) != 'null')
4988				return Form.Validator.getMsg('length').substitute({length: props.length, elLength: element.get('value').length});
4989			else return '';
4990		},
4991		test: function(element, props){
4992			if (typeOf(props.length) != 'null') return (element.get('value').length == props.length || element.get('value').length == 0);
4993			else return true;
4994		}
4995	}],
4996
4997	['minLength', {
4998		errorMsg: function(element, props){
4999			if (typeOf(props.minLength) != 'null')
5000				return Form.Validator.getMsg('minLength').substitute({minLength: props.minLength, length: element.get('value').length});
5001			else return '';
5002		},
5003		test: function(element, props){
5004			if (typeOf(props.minLength) != 'null') return (element.get('value').length >= (props.minLength || 0));
5005			else return true;
5006		}
5007	}],
5008
5009	['maxLength', {
5010		errorMsg: function(element, props){
5011			//props is {maxLength:10}
5012			if (typeOf(props.maxLength) != 'null')
5013				return Form.Validator.getMsg('maxLength').substitute({maxLength: props.maxLength, length: element.get('value').length});
5014			else return '';
5015		},
5016		test: function(element, props){
5017			return element.get('value').length <= (props.maxLength || 10000);
5018		}
5019	}],
5020
5021	['validate-integer', {
5022		errorMsg: Form.Validator.getMsg.pass('integer'),
5023		test: function(element){
5024			return Form.Validator.getValidator('IsEmpty').test(element) || (/^(-?[1-9]\d*|0)$/).test(element.get('value'));
5025		}
5026	}],
5027
5028	['validate-numeric', {
5029		errorMsg: Form.Validator.getMsg.pass('numeric'),
5030		test: function(element){
5031			return Form.Validator.getValidator('IsEmpty').test(element) ||
5032				(/^-?(?:0$0(?=\d*\.)|[1-9]|0)\d*(\.\d+)?$/).test(element.get('value'));
5033		}
5034	}],
5035
5036	['validate-digits', {
5037		errorMsg: Form.Validator.getMsg.pass('digits'),
5038		test: function(element){
5039			return Form.Validator.getValidator('IsEmpty').test(element) || (/^[\d() .:\-\+#]+$/.test(element.get('value')));
5040		}
5041	}],
5042
5043	['validate-alpha', {
5044		errorMsg: Form.Validator.getMsg.pass('alpha'),
5045		test: function(element){
5046			return Form.Validator.getValidator('IsEmpty').test(element) || (/^[a-zA-Z]+$/).test(element.get('value'));
5047		}
5048	}],
5049
5050	['validate-alphanum', {
5051		errorMsg: Form.Validator.getMsg.pass('alphanum'),
5052		test: function(element){
5053			return Form.Validator.getValidator('IsEmpty').test(element) || !(/\W/).test(element.get('value'));
5054		}
5055	}],
5056
5057	['validate-date', {
5058		errorMsg: function(element, props){
5059			if (Date.parse){
5060				var format = props.dateFormat || '%x';
5061				return Form.Validator.getMsg('dateSuchAs').substitute({date: new Date().format(format)});
5062			} else {
5063				return Form.Validator.getMsg('dateInFormatMDY');
5064			}
5065		},
5066		test: function(element, props){
5067			if (Form.Validator.getValidator('IsEmpty').test(element)) return true;
5068			var dateLocale = Locale.get('Date'),
5069				dateNouns = new RegExp([dateLocale.days, dateLocale.days_abbr, dateLocale.months, dateLocale.months_abbr, dateLocale.AM, dateLocale.PM].flatten().join('|'), 'i'),
5070				value = element.get('value'),
5071				wordsInValue = value.match(/[a-z]+/gi);
5072
5073			if (wordsInValue && !wordsInValue.every(dateNouns.exec, dateNouns)) return false;
5074
5075			var date = Date.parse(value);
5076			if (!date) return false;
5077
5078			var format = props.dateFormat || '%x',
5079				formatted = date.format(format);
5080			if (formatted != 'invalid date') element.set('value', formatted);
5081			return date.isValid();
5082		}
5083	}],
5084
5085	['validate-email', {
5086		errorMsg: Form.Validator.getMsg.pass('email'),
5087		test: function(element){
5088			/*
5089			var chars = "[a-z0-9!#$%&'*+/=?^_`{|}~-]",
5090				local = '(?:' + chars + '\\.?){0,63}' + chars,
5091
5092				label = '[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?',
5093				hostname = '(?:' + label + '\\.)*' + label;
5094
5095				octet = '(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)',
5096				ipv4 = '\\[(?:' + octet + '\\.){3}' + octet + '\\]',
5097
5098				domain = '(?:' + hostname + '|' + ipv4 + ')';
5099
5100			var regex = new RegExp('^' + local + '@' + domain + '$', 'i');
5101			*/
5102			return Form.Validator.getValidator('IsEmpty').test(element) || (/^(?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]\.?){0,63}[a-z0-9!#$%&'*+\/=?^_`{|}~-]@(?:(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\])$/i).test(element.get('value'));
5103		}
5104	}],
5105
5106	['validate-url', {
5107		errorMsg: Form.Validator.getMsg.pass('url'),
5108		test: function(element){
5109			return Form.Validator.getValidator('IsEmpty').test(element) || (/^(https?|ftp|rmtp|mms):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i).test(element.get('value'));
5110		}
5111	}],
5112
5113	['validate-currency-dollar', {
5114		errorMsg: Form.Validator.getMsg.pass('currencyDollar'),
5115		test: function(element){
5116			return Form.Validator.getValidator('IsEmpty').test(element) || (/^\$?\-?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/).test(element.get('value'));
5117		}
5118	}],
5119
5120	['validate-one-required', {
5121		errorMsg: Form.Validator.getMsg.pass('oneRequired'),
5122		test: function(element, props){
5123			var p = document.id(props['validate-one-required']) || element.getParent(props['validate-one-required']);
5124			return p.getElements('input').some(function(el){
5125				if (['checkbox', 'radio'].contains(el.get('type'))) return el.get('checked');
5126				return el.get('value');
5127			});
5128		}
5129	}]
5130
5131]);
5132
5133Element.Properties.validator = {
5134
5135	set: function(options){
5136		this.get('validator').setOptions(options);
5137	},
5138
5139	get: function(){
5140		var validator = this.retrieve('validator');
5141		if (!validator){
5142			validator = new Form.Validator(this);
5143			this.store('validator', validator);
5144		}
5145		return validator;
5146	}
5147
5148};
5149
5150Element.implement({
5151
5152	validate: function(options){
5153		if (options) this.set('validator', options);
5154		return this.get('validator').validate();
5155	}
5156
5157});
5158
5159
5160
5161
5162
5163
5164/*
5165---
5166
5167script: Form.Validator.Extras.js
5168
5169name: Form.Validator.Extras
5170
5171description: Additional validators for the Form.Validator class.
5172
5173license: MIT-style license
5174
5175authors:
5176  - Aaron Newton
5177
5178requires:
5179  - Form.Validator
5180
5181provides: [Form.Validator.Extras]
5182
5183...
5184*/
5185
5186(function(){
5187
5188function getItems(props, preference, children, cssSelector){
5189	if (preference && props[preference]) return props[preference];
5190	var el = document.id(props[children]);
5191	if (!el) return [];
5192	return el.getElements(cssSelector);
5193}
5194
5195Form.Validator.addAllThese([
5196
5197	['validate-enforce-oncheck', {
5198		test: function(element, props){
5199			var fv = element.getParent('form').retrieve('validator');
5200			if (!fv) return true;
5201			getItems(props, 'toEnforce', 'enforceChildrenOf', 'input, select, textarea').each(function(item){
5202				if (element.checked){
5203					fv.enforceField(item);
5204				} else {
5205					fv.ignoreField(item);
5206					fv.resetField(item);
5207				}
5208			});
5209			return true;
5210		}
5211	}],
5212
5213	['validate-ignore-oncheck', {
5214		test: function(element, props){
5215			var fv = element.getParent('form').retrieve('validator');
5216			if (!fv) return true;
5217			getItems(props, 'toIgnore', 'ignoreChildrenOf', 'input, select, textarea').each(function(item){
5218				if (element.checked){
5219					fv.ignoreField(item);
5220					fv.resetField(item);
5221				} else {
5222					fv.enforceField(item);
5223				}
5224			});
5225			return true;
5226		}
5227	}],
5228
5229	['validate-enforce-onselect-value', {
5230		test: function(element, props){
5231			if (!props.value) return true;
5232			var fv = element.getParent('form').retrieve('validator');
5233			if (!fv) return true;
5234			getItems(props, 'toEnforce', 'enforceChildrenOf', 'input, select, textarea').each(function(item){
5235				if (props.value == element.value){
5236					fv.enforceField(item);
5237				} else {
5238					fv.ignoreField(item);
5239					fv.resetField(item);
5240				}
5241			});
5242			return true;
5243		}
5244	}],
5245
5246	['validate-nospace', {
5247		errorMsg: function(){
5248			return Form.Validator.getMsg('noSpace');
5249		},
5250		test: function(element, props){
5251			return !element.get('value').test(/\s/);
5252		}
5253	}],
5254
5255	['validate-toggle-oncheck', {
5256		test: function(element, props){
5257			var fv = element.getParent('form').retrieve('validator');
5258			if (!fv) return true;
5259			var eleArr = getItems(props, 'toToggle', 'toToggleChildrenOf', 'input, select, textarea');
5260			if (!element.checked){
5261				eleArr.each(function(item){
5262					fv.ignoreField(item);
5263					fv.resetField(item);
5264				});
5265			} else {
5266				eleArr.each(function(item){
5267					fv.enforceField(item);
5268				});
5269			}
5270			return true;
5271		}
5272	}],
5273
5274	['validate-reqchk-bynode', {
5275		errorMsg: function(){
5276			return Form.Validator.getMsg('reqChkByNode');
5277		},
5278		test: function(element, props){
5279			return getItems(props, false, 'nodeId', props.selector || 'input[type=checkbox], input[type=radio]').some(function(item){
5280				return item.checked;
5281			});
5282		}
5283	}],
5284
5285	['validate-required-check', {
5286		errorMsg: function(element, props){
5287			return props.useTitle ? element.get('title') : Form.Validator.getMsg('requiredChk');
5288		},
5289		test: function(element, props){
5290			return !!element.checked;
5291		}
5292	}],
5293
5294	['validate-reqchk-byname', {
5295		errorMsg: function(element, props){
5296			return Form.Validator.getMsg('reqChkByName').substitute({label: props.label || element.get('type')});
5297		},
5298		test: function(element, props){
5299			var grpName = props.groupName || element.get('name');
5300			var grpNameEls = $$('[name=' + grpName +']');
5301			var oneCheckedItem = grpNameEls.some(function(item, index){
5302				return item.checked;
5303			});
5304			var fv = element.getParent('form').retrieve('validator');
5305			if (oneCheckedItem && fv){
5306				grpNameEls.each(function(item, index){ fv.resetField(item); });
5307			}
5308			return oneCheckedItem;
5309		}
5310	}],
5311
5312	['validate-match', {
5313		errorMsg: function(element, props){
5314			return Form.Validator.getMsg('match').substitute({matchName: decodeURIComponent((props.matchName+'').replace(/\+/g, '%20')) || document.id(props.matchInput).get('name')});
5315		},
5316		test: function(element, props){
5317			var eleVal = element.get('value');
5318			var matchVal = document.id(props.matchInput) && document.id(props.matchInput).get('value');
5319			return eleVal && matchVal ? eleVal == matchVal : true;
5320		}
5321	}],
5322
5323	['validate-after-date', {
5324		errorMsg: function(element, props){
5325			return Form.Validator.getMsg('afterDate').substitute({
5326				label: props.afterLabel || (props.afterElement ? Form.Validator.getMsg('startDate') : Form.Validator.getMsg('currentDate'))
5327			});
5328		},
5329		test: function(element, props){
5330			var start = document.id(props.afterElement) ? Date.parse(document.id(props.afterElement).get('value')) : new Date();
5331			var end = Date.parse(element.get('value'));
5332			return end && start ? end >= start : true;
5333		}
5334	}],
5335
5336	['validate-before-date', {
5337		errorMsg: function(element, props){
5338			return Form.Validator.getMsg('beforeDate').substitute({
5339				label: props.beforeLabel || (props.beforeElement ? Form.Validator.getMsg('endDate') : Form.Validator.getMsg('currentDate'))
5340			});
5341		},
5342		test: function(element, props){
5343			var start = Date.parse(element.get('value'));
5344			var end = document.id(props.beforeElement) ? Date.parse(document.id(props.beforeElement).get('value')) : new Date();
5345			return end && start ? end >= start : true;
5346		}
5347	}],
5348
5349	['validate-custom-required', {
5350		errorMsg: function(){
5351			return Form.Validator.getMsg('required');
5352		},
5353		test: function(element, props){
5354			return element.get('value') != props.emptyValue;
5355		}
5356	}],
5357
5358	['validate-same-month', {
5359		errorMsg: function(element, props){
5360			var startMo = document.id(props.sameMonthAs) && document.id(props.sameMonthAs).get('value');
5361			var eleVal = element.get('value');
5362			if (eleVal != '') return Form.Validator.getMsg(startMo ? 'sameMonth' : 'startMonth');
5363		},
5364		test: function(element, props){
5365			var d1 = Date.parse(element.get('value'));
5366			var d2 = Date.parse(document.id(props.sameMonthAs) && document.id(props.sameMonthAs).get('value'));
5367			return d1 && d2 ? d1.format('%B') == d2.format('%B') : true;
5368		}
5369	}],
5370
5371
5372	['validate-cc-num', {
5373		errorMsg: function(element){
5374			var ccNum = element.get('value').replace(/[^0-9]/g, '');
5375			return Form.Validator.getMsg('creditcard').substitute({length: ccNum.length});
5376		},
5377		test: function(element){
5378			// required is a different test
5379			if (Form.Validator.getValidator('IsEmpty').test(element)) return true;
5380
5381			// Clean number value
5382			var ccNum = element.get('value');
5383			ccNum = ccNum.replace(/[^0-9]/g, '');
5384
5385			var validType = false;
5386
5387			if (ccNum.test(/^4[0-9]{12}([0-9]{3})?$/)) validType = 'Visa';
5388			else if (ccNum.test(/^5[1-5]([0-9]{14})$/)) validType = 'Master Card';
5389			else if (ccNum.test(/^3[47][0-9]{13}$/)) validType = 'American Express';
5390			else if (ccNum.test(/^6(?:011|5[0-9]{2})[0-9]{12}$/)) validType = 'Discover';
5391			else if (ccNum.test(/^3(?:0[0-5]|[68][0-9])[0-9]{11}$/)) validType = 'Diners Club';
5392
5393			if (validType){
5394				var sum = 0;
5395				var cur = 0;
5396
5397				for (var i=ccNum.length-1; i>=0; --i){
5398					cur = ccNum.charAt(i).toInt();
5399					if (cur == 0) continue;
5400
5401					if ((ccNum.length-i) % 2 == 0) cur += cur;
5402					if (cur > 9){
5403						cur = cur.toString().charAt(0).toInt() + cur.toString().charAt(1).toInt();
5404					}
5405
5406					sum += cur;
5407				}
5408				if ((sum % 10) == 0) return true;
5409			}
5410
5411			var chunks = '';
5412			while (ccNum != ''){
5413				chunks += ' ' + ccNum.substr(0,4);
5414				ccNum = ccNum.substr(4);
5415			}
5416
5417			element.getParent('form').retrieve('validator').ignoreField(element);
5418			element.set('value', chunks.clean());
5419			element.getParent('form').retrieve('validator').enforceField(element);
5420			return false;
5421		}
5422	}]
5423
5424]);
5425
5426})();
5427
5428/*
5429---
5430
5431script: Form.Validator.Inline.js
5432
5433name: Form.Validator.Inline
5434
5435description: Extends Form.Validator to add inline messages.
5436
5437license: MIT-style license
5438
5439authors:
5440  - Aaron Newton
5441
5442requires:
5443  - Form.Validator
5444
5445provides: [Form.Validator.Inline]
5446
5447...
5448*/
5449
5450Form.Validator.Inline = new Class({
5451
5452	Extends: Form.Validator,
5453
5454	options: {
5455		showError: function(errorElement){
5456			if (errorElement.reveal) errorElement.reveal();
5457			else errorElement.setStyle('display', 'block');
5458		},
5459		hideError: function(errorElement){
5460			if (errorElement.dissolve) errorElement.dissolve();
5461			else errorElement.setStyle('display', 'none');
5462		},
5463		scrollToErrorsOnSubmit: true,
5464		scrollToErrorsOnBlur: false,
5465		scrollToErrorsOnChange: false,
5466		scrollFxOptions: {
5467			transition: 'quad:out',
5468			offset: {
5469				y: -20
5470			}
5471		}
5472	},
5473
5474	initialize: function(form, options){
5475		this.parent(form, options);
5476		this.addEvent('onElementValidate', function(isValid, field, className, warn){
5477			var validator = this.getValidator(className);
5478			if (!isValid && validator.getError(field)){
5479				if (warn) field.addClass('warning');
5480				var advice = this.makeAdvice(className, field, validator.getError(field), warn);
5481				this.insertAdvice(advice, field);
5482				this.showAdvice(className, field);
5483			} else {
5484				this.hideAdvice(className, field);
5485			}
5486		});
5487	},
5488
5489	makeAdvice: function(className, field, error, warn){
5490		var errorMsg = (warn) ? this.warningPrefix : this.errorPrefix;
5491		errorMsg += (this.options.useTitles) ? field.title || error:error;
5492		var cssClass = (warn) ? 'warning-advice' : 'validation-advice';
5493		var advice = this.getAdvice(className, field);
5494		if (advice){
5495			advice = advice.set('html', errorMsg);
5496		} else {
5497			advice = new Element('div', {
5498				html: errorMsg,
5499				styles: { display: 'none' },
5500				id: 'advice-' + className.split(':')[0] + '-' + this.getFieldId(field)
5501			}).addClass(cssClass);
5502		}
5503		field.store('$moo:advice-' + className, advice);
5504		return advice;
5505	},
5506
5507	getFieldId : function(field){
5508		return field.id ? field.id : field.id = 'input_' + field.name;
5509	},
5510
5511	showAdvice: function(className, field){
5512		var advice = this.getAdvice(className, field);
5513		if (
5514			advice &&
5515			!field.retrieve('$moo:' + this.getPropName(className)) &&
5516			(
5517				advice.getStyle('display') == 'none' ||
5518				advice.getStyle('visibility') == 'hidden' ||
5519				advice.getStyle('opacity') == 0
5520			)
5521		){
5522			field.store('$moo:' + this.getPropName(className), true);
5523			this.options.showError(advice);
5524			this.fireEvent('showAdvice', [field, advice, className]);
5525		}
5526	},
5527
5528	hideAdvice: function(className, field){
5529		var advice = this.getAdvice(className, field);
5530		if (advice && field.retrieve('$moo:' + this.getPropName(className))){
5531			field.store('$moo:' + this.getPropName(className), false);
5532			this.options.hideError(advice);
5533			this.fireEvent('hideAdvice', [field, advice, className]);
5534		}
5535	},
5536
5537	getPropName: function(className){
5538		return 'advice' + className;
5539	},
5540
5541	resetField: function(field){
5542		field = document.id(field);
5543		if (!field) return this;
5544		this.parent(field);
5545		field.get('validators').each(function(className){
5546			this.hideAdvice(className, field);
5547		}, this);
5548		return this;
5549	},
5550
5551	getAllAdviceMessages: function(field, force){
5552		var advice = [];
5553		if (field.hasClass('ignoreValidation') && !force) return advice;
5554		var validators = field.get('validators').some(function(cn){
5555			var warner = cn.test('^warn-') || field.hasClass('warnOnly');
5556			if (warner) cn = cn.replace(/^warn-/, '');
5557			var validator = this.getValidator(cn);
5558			if (!validator) return;
5559			advice.push({
5560				message: validator.getError(field),
5561				warnOnly: warner,
5562				passed: validator.test(),
5563				validator: validator
5564			});
5565		}, this);
5566		return advice;
5567	},
5568
5569	getAdvice: function(className, field){
5570		return field.retrieve('$moo:advice-' + className);
5571	},
5572
5573	insertAdvice: function(advice, field){
5574		//Check for error position prop
5575		var props = field.get('validatorProps');
5576		//Build advice
5577		if (!props.msgPos || !document.id(props.msgPos)){
5578			if (field.type && field.type.toLowerCase() == 'radio') field.getParent().adopt(advice);
5579			else advice.inject(document.id(field), 'after');
5580		} else {
5581			document.id(props.msgPos).grab(advice);
5582		}
5583	},
5584
5585	validateField: function(field, force, scroll){
5586		var result = this.parent(field, force);
5587		if (((this.options.scrollToErrorsOnSubmit && scroll == null) || scroll) && !result){
5588			var failed = document.id(this).getElement('.validation-failed');
5589			var par = document.id(this).getParent();
5590			while (par != document.body && par.getScrollSize().y == par.getSize().y){
5591				par = par.getParent();
5592			}
5593			var fx = par.retrieve('$moo:fvScroller');
5594			if (!fx && window.Fx && Fx.Scroll){
5595				fx = new Fx.Scroll(par, this.options.scrollFxOptions);
5596				par.store('$moo:fvScroller', fx);
5597			}
5598			if (failed){
5599				if (fx) fx.toElement(failed);
5600				else par.scrollTo(par.getScroll().x, failed.getPosition(par).y - 20);
5601			}
5602		}
5603		return result;
5604	},
5605
5606	watchFields: function(fields){
5607		fields.each(function(el){
5608			if (this.options.evaluateFieldsOnBlur){
5609				el.addEvent('blur', this.validationMonitor.pass([el, false, this.options.scrollToErrorsOnBlur], this));
5610			}
5611			if (this.options.evaluateFieldsOnChange){
5612				el.addEvent('change', this.validationMonitor.pass([el, true, this.options.scrollToErrorsOnChange], this));
5613			}
5614		}, this);
5615	}
5616
5617});
5618
5619/*
5620---
5621
5622script: OverText.js
5623
5624name: OverText
5625
5626description: Shows text over an input that disappears when the user clicks into it. The text remains hidden if the user adds a value.
5627
5628license: MIT-style license
5629
5630authors:
5631  - Aaron Newton
5632
5633requires:
5634  - Core/Options
5635  - Core/Events
5636  - Core/Element.Event
5637  - Class.Binds
5638  - Class.Occlude
5639  - Element.Position
5640  - Element.Shortcuts
5641
5642provides: [OverText]
5643
5644...
5645*/
5646(function(){
5647
5648var OverText = this.OverText = new Class({
5649
5650	Implements: [Options, Events, Class.Occlude],
5651
5652	Binds: ['reposition', 'assert', 'focus', 'hide'],
5653
5654	options: {/*
5655		textOverride: null,
5656		onFocus: function(){},
5657		onTextHide: function(textEl, inputEl){},
5658		onTextShow: function(textEl, inputEl){}, */
5659		element: 'label',
5660		labelClass: 'overTxtLabel',
5661		positionOptions: {
5662			position: 'upperLeft',
5663			edge: 'upperLeft',
5664			offset: {
5665				x: 4,
5666				y: 2
5667			}
5668		},
5669		poll: false,
5670		pollInterval: 250,
5671		wrap: false
5672	},
5673
5674	property: 'OverText',
5675
5676	initialize: function(element, options){
5677		element = this.element = document.id(element);
5678
5679		if (this.occlude()) return this.occluded;
5680		this.setOptions(options);
5681
5682		this.attach(element);
5683		OverText.instances.push(this);
5684
5685		if (this.options.poll) this.poll();
5686	},
5687
5688	toElement: function(){
5689		return this.element;
5690	},
5691
5692	attach: function(){
5693		var element = this.element,
5694			options = this.options,
5695			value = options.textOverride || element.get('alt') || element.get('title');
5696
5697		if (!value) return this;
5698
5699		var text = this.text = new Element(options.element, {
5700			'class': options.labelClass,
5701			styles: {
5702				lineHeight: 'normal',
5703				position: 'absolute',
5704				cursor: 'text'
5705			},
5706			html: value,
5707			events: {
5708				click: this.hide.pass(options.element == 'label', this)
5709			}
5710		}).inject(element, 'after');
5711
5712		if (options.element == 'label'){
5713			if (!element.get('id')) element.set('id', 'input_' + String.uniqueID());
5714			text.set('for', element.get('id'));
5715		}
5716
5717		if (options.wrap){
5718			this.textHolder = new Element('div.overTxtWrapper', {
5719				styles: {
5720					lineHeight: 'normal',
5721					position: 'relative'
5722				}
5723			}).grab(text).inject(element, 'before');
5724		}
5725
5726		return this.enable();
5727	},
5728
5729	destroy: function(){
5730		this.element.eliminate(this.property); // Class.Occlude storage
5731		this.disable();
5732		if (this.text) this.text.destroy();
5733		if (this.textHolder) this.textHolder.destroy();
5734		return this;
5735	},
5736
5737	disable: function(){
5738		this.element.removeEvents({
5739			focus: this.focus,
5740			blur: this.assert,
5741			change: this.assert
5742		});
5743		window.removeEvent('resize', this.reposition);
5744		this.hide(true, true);
5745		return this;
5746	},
5747
5748	enable: function(){
5749		this.element.addEvents({
5750			focus: this.focus,
5751			blur: this.assert,
5752			change: this.assert
5753		});
5754		window.addEvent('resize', this.reposition);
5755		this.reposition();
5756		return this;
5757	},
5758
5759	wrap: function(){
5760		if (this.options.element == 'label'){
5761			if (!this.element.get('id')) this.element.set('id', 'input_' + String.uniqueID());
5762			this.text.set('for', this.element.get('id'));
5763		}
5764	},
5765
5766	startPolling: function(){
5767		this.pollingPaused = false;
5768		return this.poll();
5769	},
5770
5771	poll: function(stop){
5772		//start immediately
5773		//pause on focus
5774		//resumeon blur
5775		if (this.poller && !stop) return this;
5776		if (stop){
5777			clearInterval(this.poller);
5778		} else {
5779			this.poller = (function(){
5780				if (!this.pollingPaused) this.assert(true);
5781			}).periodical(this.options.pollInterval, this);
5782		}
5783
5784		return this;
5785	},
5786
5787	stopPolling: function(){
5788		this.pollingPaused = true;
5789		return this.poll(true);
5790	},
5791
5792	focus: function(){
5793		if (this.text && (!this.text.isDisplayed() || this.element.get('disabled'))) return this;
5794		return this.hide();
5795	},
5796
5797	hide: function(suppressFocus, force){
5798		if (this.text && (this.text.isDisplayed() && (!this.element.get('disabled') || force))){
5799			this.text.hide();
5800			this.fireEvent('textHide', [this.text, this.element]);
5801			this.pollingPaused = true;
5802			if (!suppressFocus){
5803				try {
5804					this.element.fireEvent('focus');
5805					this.element.focus();
5806				} catch (e){} //IE barfs if you call focus on hidden elements
5807			}
5808		}
5809		return this;
5810	},
5811
5812	show: function(){
5813		if (document.id(this.text) && !this.text.isDisplayed()){
5814			this.text.show();
5815			this.reposition();
5816			this.fireEvent('textShow', [this.text, this.element]);
5817			this.pollingPaused = false;
5818		}
5819		return this;
5820	},
5821
5822	test: function(){
5823		return !this.element.get('value');
5824	},
5825
5826	assert: function(suppressFocus){
5827		return this[this.test() ? 'show' : 'hide'](suppressFocus);
5828	},
5829
5830	reposition: function(){
5831		this.assert(true);
5832		if (!this.element.isVisible()) return this.stopPolling().hide();
5833		if (this.text && this.test()){
5834			this.text.position(Object.merge(this.options.positionOptions, {
5835				relativeTo: this.element
5836			}));
5837		}
5838		return this;
5839	}
5840
5841});
5842
5843})();
5844
5845OverText.instances = [];
5846
5847Object.append(OverText, {
5848
5849	each: function(fn){
5850		return OverText.instances.each(function(ot, i){
5851			if (ot.element && ot.text) fn.call(OverText, ot, i);
5852		});
5853	},
5854
5855	update: function(){
5856
5857		return OverText.each(function(ot){
5858			return ot.reposition();
5859		});
5860
5861	},
5862
5863	hideAll: function(){
5864
5865		return OverText.each(function(ot){
5866			return ot.hide(true, true);
5867		});
5868
5869	},
5870
5871	showAll: function(){
5872		return OverText.each(function(ot){
5873			return ot.show();
5874		});
5875	}
5876
5877});
5878
5879
5880/*
5881---
5882
5883script: Fx.Elements.js
5884
5885name: Fx.Elements
5886
5887description: Effect to change any number of CSS properties of any number of Elements.
5888
5889license: MIT-style license
5890
5891authors:
5892  - Valerio Proietti
5893
5894requires:
5895  - Core/Fx.CSS
5896  - MooTools.More
5897
5898provides: [Fx.Elements]
5899
5900...
5901*/
5902
5903Fx.Elements = new Class({
5904
5905	Extends: Fx.CSS,
5906
5907	initialize: function(elements, options){
5908		this.elements = this.subject = $$(elements);
5909		this.parent(options);
5910	},
5911
5912	compute: function(from, to, delta){
5913		var now = {};
5914
5915		for (var i in from){
5916			var iFrom = from[i], iTo = to[i], iNow = now[i] = {};
5917			for (var p in iFrom) iNow[p] = this.parent(iFrom[p], iTo[p], delta);
5918		}
5919
5920		return now;
5921	},
5922
5923	set: function(now){
5924		for (var i in now){
5925			if (!this.elements[i]) continue;
5926
5927			var iNow = now[i];
5928			for (var p in iNow) this.render(this.elements[i], p, iNow[p], this.options.unit);
5929		}
5930
5931		return this;
5932	},
5933
5934	start: function(obj){
5935		if (!this.check(obj)) return this;
5936		var from = {}, to = {};
5937
5938		for (var i in obj){
5939			if (!this.elements[i]) continue;
5940
5941			var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {};
5942
5943			for (var p in iProps){
5944				var parsed = this.prepare(this.elements[i], p, iProps[p]);
5945				iFrom[p] = parsed.from;
5946				iTo[p] = parsed.to;
5947			}
5948		}
5949
5950		return this.parent(from, to);
5951	}
5952
5953});
5954
5955/*
5956---
5957
5958script: Fx.Accordion.js
5959
5960name: Fx.Accordion
5961
5962description: An Fx.Elements extension which allows you to easily create accordion type controls.
5963
5964license: MIT-style license
5965
5966authors:
5967  - Valerio Proietti
5968
5969requires:
5970  - Core/Element.Event
5971  - Fx.Elements
5972
5973provides: [Fx.Accordion]
5974
5975...
5976*/
5977
5978Fx.Accordion = new Class({
5979
5980	Extends: Fx.Elements,
5981
5982	options: {/*
5983		onActive: function(toggler, section){},
5984		onBackground: function(toggler, section){},*/
5985		fixedHeight: false,
5986		fixedWidth: false,
5987		display: 0,
5988		show: false,
5989		height: true,
5990		width: false,
5991		opacity: true,
5992		alwaysHide: false,
5993		trigger: 'click',
5994		initialDisplayFx: true,
5995		resetHeight: true,
5996		keepOpen: false
5997	},
5998
5999	initialize: function(){
6000		var defined = function(obj){
6001			return obj != null;
6002		};
6003
6004		var params = Array.link(arguments, {
6005			'container': Type.isElement, //deprecated
6006			'options': Type.isObject,
6007			'togglers': defined,
6008			'elements': defined
6009		});
6010		this.parent(params.elements, params.options);
6011
6012		var options = this.options,
6013			togglers = this.togglers = $$(params.togglers);
6014
6015		this.previous = -1;
6016		this.internalChain = new Chain();
6017
6018		if (options.alwaysHide) this.options.link = 'chain';
6019
6020		if (options.show || this.options.show === 0){
6021			options.display = false;
6022			this.previous = options.show;
6023		}
6024
6025		if (options.start){
6026			options.display = false;
6027			options.show = false;
6028		}
6029
6030		var effects = this.effects = {};
6031
6032		if (options.opacity) effects.opacity = 'fullOpacity';
6033		if (options.width) effects.width = options.fixedWidth ? 'fullWidth' : 'offsetWidth';
6034		if (options.height) effects.height = options.fixedHeight ? 'fullHeight' : 'scrollHeight';
6035
6036		for (var i = 0, l = togglers.length; i < l; i++) this.addSection(togglers[i], this.elements[i]);
6037
6038		this.elements.each(function(el, i){
6039			if (options.show === i){
6040				this.fireEvent('active', [togglers[i], el]);
6041			} else {
6042				for (var fx in effects) el.setStyle(fx, 0);
6043			}
6044		}, this);
6045
6046		if (options.display || options.display === 0 || options.initialDisplayFx === false){
6047			this.display(options.display, options.initialDisplayFx);
6048		}
6049
6050		if (options.fixedHeight !== false) options.resetHeight = false;
6051		this.addEvent('complete', this.internalChain.callChain.bind(this.internalChain));
6052	},
6053
6054	addSection: function(toggler, element){
6055		toggler = document.id(toggler);
6056		element = document.id(element);
6057		this.togglers.include(toggler);
6058		this.elements.include(element);
6059
6060		var togglers = this.togglers,
6061			options = this.options,
6062			test = togglers.contains(toggler),
6063			idx = togglers.indexOf(toggler),
6064			displayer = this.display.pass(idx, this);
6065
6066		toggler.store('accordion:display', displayer)
6067			.addEvent(options.trigger, displayer);
6068
6069		if (options.height) element.setStyles({'padding-top': 0, 'border-top': 'none', 'padding-bottom': 0, 'border-bottom': 'none'});
6070		if (options.width) element.setStyles({'padding-left': 0, 'border-left': 'none', 'padding-right': 0, 'border-right': 'none'});
6071
6072		element.fullOpacity = 1;
6073		if (options.fixedWidth) element.fullWidth = options.fixedWidth;
6074		if (options.fixedHeight) element.fullHeight = options.fixedHeight;
6075		element.setStyle('overflow', 'hidden');
6076
6077		if (!test) for (var fx in this.effects){
6078			element.setStyle(fx, 0);
6079		}
6080		return this;
6081	},
6082
6083	removeSection: function(toggler, displayIndex){
6084		var togglers = this.togglers,
6085			idx = togglers.indexOf(toggler),
6086			element = this.elements[idx];
6087
6088		var remover = function(){
6089			togglers.erase(toggler);
6090			this.elements.erase(element);
6091			this.detach(toggler);
6092		}.bind(this);
6093
6094		if (this.now == idx || displayIndex != null){
6095			this.display(displayIndex != null ? displayIndex : (idx - 1 >= 0 ? idx - 1 : 0)).chain(remover);
6096		} else {
6097			remover();
6098		}
6099		return this;
6100	},
6101
6102	detach: function(toggler){
6103		var remove = function(toggler){
6104			toggler.removeEvent(this.options.trigger, toggler.retrieve('accordion:display'));
6105		}.bind(this);
6106
6107		if (!toggler) this.togglers.each(remove);
6108		else remove(toggler);
6109		return this;
6110	},
6111
6112	display: function(index, useFx){
6113		if (!this.check(index, useFx)) return this;
6114
6115		var obj = {},
6116			elements = this.elements,
6117			options = this.options,
6118			effects = this.effects,
6119			keepOpen = options.keepOpen,
6120			alwaysHide = options.alwaysHide;
6121
6122		if (useFx == null) useFx = true;
6123		if (typeOf(index) == 'element') index = elements.indexOf(index);
6124		if (index == this.current && !alwaysHide && !keepOpen) return this;
6125
6126		if (options.resetHeight){
6127			var prev = elements[this.current];
6128			if (prev && !this.selfHidden){
6129				for (var fx in effects) prev.setStyle(fx, prev[effects[fx]]);
6130			}
6131		}
6132
6133		if (this.timer && options.link == 'chain') return this;
6134
6135		if (this.current != null) this.previous = this.current;
6136		this.current = index;
6137		this.selfHidden = false;
6138
6139		elements.each(function(el, i){
6140			obj[i] = {};
6141			var hide, isOpen;
6142			if (!keepOpen || i == index){
6143				if (i == index) isOpen = (el.offsetHeight > 0 && options.height) || (el.offsetWidth > 0 && options.width);
6144
6145				if (i != index){
6146					hide = true;
6147				} else if ((alwaysHide || keepOpen) && isOpen){
6148					hide = true;
6149					this.selfHidden = true;
6150				}
6151				this.fireEvent(hide ? 'background' : 'active', [this.togglers[i], el]);
6152				for (var fx in effects) obj[i][fx] = hide ? 0 : el[effects[fx]];
6153				if (!useFx && !hide && options.resetHeight) obj[i].height = 'auto';
6154			}
6155		}, this);
6156
6157		this.internalChain.clearChain();
6158		this.internalChain.chain(function(){
6159			if (options.resetHeight && !this.selfHidden){
6160				var el = elements[index];
6161				if (el) el.setStyle('height', 'auto');
6162			}
6163		}.bind(this));
6164
6165		return useFx ? this.start(obj) : this.set(obj).internalChain.callChain();
6166	}
6167
6168});
6169
6170
6171
6172/*
6173---
6174
6175script: Fx.Move.js
6176
6177name: Fx.Move
6178
6179description: Defines Fx.Move, a class that works with Element.Position.js to transition an element from one location to another.
6180
6181license: MIT-style license
6182
6183authors:
6184  - Aaron Newton
6185
6186requires:
6187  - Core/Fx.Morph
6188  - Element.Position
6189
6190provides: [Fx.Move]
6191
6192...
6193*/
6194
6195Fx.Move = new Class({
6196
6197	Extends: Fx.Morph,
6198
6199	options: {
6200		relativeTo: document.body,
6201		position: 'center',
6202		edge: false,
6203		offset: {x: 0, y: 0}
6204	},
6205
6206	start: function(destination){
6207		var element = this.element,
6208			topLeft = element.getStyles('top', 'left');
6209		if (topLeft.top == 'auto' || topLeft.left == 'auto'){
6210			element.setPosition(element.getPosition(element.getOffsetParent()));
6211		}
6212		return this.parent(element.position(Object.merge({}, this.options, destination, {returnPos: true})));
6213	}
6214
6215});
6216
6217Element.Properties.move = {
6218
6219	set: function(options){
6220		this.get('move').cancel().setOptions(options);
6221		return this;
6222	},
6223
6224	get: function(){
6225		var move = this.retrieve('move');
6226		if (!move){
6227			move = new Fx.Move(this, {link: 'cancel'});
6228			this.store('move', move);
6229		}
6230		return move;
6231	}
6232
6233};
6234
6235Element.implement({
6236
6237	move: function(options){
6238		this.get('move').start(options);
6239		return this;
6240	}
6241
6242});
6243
6244/*
6245---
6246
6247script: Fx.Scroll.js
6248
6249name: Fx.Scroll
6250
6251description: Effect to smoothly scroll any element, including the window.
6252
6253license: MIT-style license
6254
6255authors:
6256  - Valerio Proietti
6257
6258requires:
6259  - Core/Fx
6260  - Core/Element.Event
6261  - Core/Element.Dimensions
6262  - MooTools.More
6263
6264provides: [Fx.Scroll]
6265
6266...
6267*/
6268
6269(function(){
6270
6271Fx.Scroll = new Class({
6272
6273	Extends: Fx,
6274
6275	options: {
6276		offset: {x: 0, y: 0},
6277		wheelStops: true
6278	},
6279
6280	initialize: function(element, options){
6281		this.element = this.subject = document.id(element);
6282		this.parent(options);
6283
6284		if (typeOf(this.element) != 'element') this.element = document.id(this.element.getDocument().body);
6285
6286		if (this.options.wheelStops){
6287			var stopper = this.element,
6288				cancel = this.cancel.pass(false, this);
6289			this.addEvent('start', function(){
6290				stopper.addEvent('mousewheel', cancel);
6291			}, true);
6292			this.addEvent('complete', function(){
6293				stopper.removeEvent('mousewheel', cancel);
6294			}, true);
6295		}
6296	},
6297
6298	set: function(){
6299		var now = Array.flatten(arguments);
6300		this.element.scrollTo(now[0], now[1]);
6301		return this;
6302	},
6303
6304	compute: function(from, to, delta){
6305		return [0, 1].map(function(i){
6306			return Fx.compute(from[i], to[i], delta);
6307		});
6308	},
6309
6310	start: function(x, y){
6311		if (!this.check(x, y)) return this;
6312		var scroll = this.element.getScroll();
6313		return this.parent([scroll.x, scroll.y], [x, y]);
6314	},
6315
6316	calculateScroll: function(x, y){
6317		var element = this.element,
6318			scrollSize = element.getScrollSize(),
6319			scroll = element.getScroll(),
6320			size = element.getSize(),
6321			offset = this.options.offset,
6322			values = {x: x, y: y};
6323
6324		for (var z in values){
6325			if (!values[z] && values[z] !== 0) values[z] = scroll[z];
6326			if (typeOf(values[z]) != 'number') values[z] = scrollSize[z] - size[z];
6327			values[z] += offset[z];
6328		}
6329
6330		return [values.x, values.y];
6331	},
6332
6333	toTop: function(){
6334		return this.start.apply(this, this.calculateScroll(false, 0));
6335	},
6336
6337	toLeft: function(){
6338		return this.start.apply(this, this.calculateScroll(0, false));
6339	},
6340
6341	toRight: function(){
6342		return this.start.apply(this, this.calculateScroll('right', false));
6343	},
6344
6345	toBottom: function(){
6346		return this.start.apply(this, this.calculateScroll(false, 'bottom'));
6347	},
6348
6349	toElement: function(el, axes){
6350		axes = axes ? Array.convert(axes) : ['x', 'y'];
6351		var scroll = isBody(this.element) ? {x: 0, y: 0} : this.element.getScroll();
6352		var position = Object.map(document.id(el).getPosition(this.element), function(value, axis){
6353			return axes.contains(axis) ? value + scroll[axis] : false;
6354		});
6355		return this.start.apply(this, this.calculateScroll(position.x, position.y));
6356	},
6357
6358	toElementEdge: function(el, axes, offset){
6359		axes = axes ? Array.convert(axes) : ['x', 'y'];
6360		el = document.id(el);
6361		var to = {},
6362			position = el.getPosition(this.element),
6363			size = el.getSize(),
6364			scroll = this.element.getScroll(),
6365			containerSize = this.element.getSize(),
6366			edge = {
6367				x: position.x + size.x,
6368				y: position.y + size.y
6369			};
6370
6371		['x', 'y'].each(function(axis){
6372			if (axes.contains(axis)){
6373				if (edge[axis] > scroll[axis] + containerSize[axis]) to[axis] = edge[axis] - containerSize[axis];
6374				if (position[axis] < scroll[axis]) to[axis] = position[axis];
6375			}
6376			if (to[axis] == null) to[axis] = scroll[axis];
6377			if (offset && offset[axis]) to[axis] = to[axis] + offset[axis];
6378		}, this);
6379
6380		if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y);
6381		return this;
6382	},
6383
6384	toElementCenter: function(el, axes, offset){
6385		axes = axes ? Array.convert(axes) : ['x', 'y'];
6386		el = document.id(el);
6387		var to = {},
6388			position = el.getPosition(this.element),
6389			size = el.getSize(),
6390			scroll = this.element.getScroll(),
6391			containerSize = this.element.getSize();
6392
6393		['x', 'y'].each(function(axis){
6394			if (axes.contains(axis)){
6395				to[axis] = position[axis] - (containerSize[axis] - size[axis]) / 2;
6396			}
6397			if (to[axis] == null) to[axis] = scroll[axis];
6398			if (offset && offset[axis]) to[axis] = to[axis] + offset[axis];
6399		}, this);
6400
6401		if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y);
6402		return this;
6403	}
6404
6405});
6406
6407
6408
6409function isBody(element){
6410	return (/^(?:body|html)$/i).test(element.tagName);
6411}
6412
6413})();
6414
6415/*
6416---
6417
6418script: Fx.Slide.js
6419
6420name: Fx.Slide
6421
6422description: Effect to slide an element in and out of view.
6423
6424license: MIT-style license
6425
6426authors:
6427  - Valerio Proietti
6428
6429requires:
6430  - Core/Fx
6431  - Core/Element.Style
6432  - MooTools.More
6433
6434provides: [Fx.Slide]
6435
6436...
6437*/
6438
6439Fx.Slide = new Class({
6440
6441	Extends: Fx,
6442
6443	options: {
6444		mode: 'vertical',
6445		wrapper: false,
6446		hideOverflow: true,
6447		resetHeight: false
6448	},
6449
6450	initialize: function(element, options){
6451		element = this.element = this.subject = document.id(element);
6452		this.parent(options);
6453		options = this.options;
6454
6455		var wrapper = element.retrieve('wrapper'),
6456			styles = element.getStyles('margin', 'position', 'overflow');
6457
6458		if (options.hideOverflow) styles = Object.append(styles, {overflow: 'hidden'});
6459		if (options.wrapper) wrapper = document.id(options.wrapper).setStyles(styles);
6460
6461		if (!wrapper) wrapper = new Element('div', {
6462			styles: styles
6463		}).wraps(element);
6464
6465		element.store('wrapper', wrapper).setStyle('margin', 0);
6466		if (element.getStyle('overflow') == 'visible') element.setStyle('overflow', 'hidden');
6467
6468		this.now = [];
6469		this.open = true;
6470		this.wrapper = wrapper;
6471
6472		this.addEvent('complete', function(){
6473			this.open = (wrapper['offset' + this.layout.capitalize()] != 0);
6474			if (this.open && this.options.resetHeight) wrapper.setStyle('height', '');
6475		}, true);
6476	},
6477
6478	vertical: function(){
6479		this.margin = 'margin-top';
6480		this.layout = 'height';
6481		this.offset = this.element.offsetHeight;
6482	},
6483
6484	horizontal: function(){
6485		this.margin = 'margin-left';
6486		this.layout = 'width';
6487		this.offset = this.element.offsetWidth;
6488	},
6489
6490	set: function(now){
6491		this.element.setStyle(this.margin, now[0]);
6492		this.wrapper.setStyle(this.layout, now[1]);
6493		return this;
6494	},
6495
6496	compute: function(from, to, delta){
6497		return [0, 1].map(function(i){
6498			return Fx.compute(from[i], to[i], delta);
6499		});
6500	},
6501
6502	start: function(how, mode){
6503		if (!this.check(how, mode)) return this;
6504		this[mode || this.options.mode]();
6505
6506		var margin = this.element.getStyle(this.margin).toInt(),
6507			layout = this.wrapper.getStyle(this.layout).toInt(),
6508			caseIn = [[margin, layout], [0, this.offset]],
6509			caseOut = [[margin, layout], [-this.offset, 0]],
6510			start;
6511
6512		switch (how){
6513			case 'in': start = caseIn; break;
6514			case 'out': start = caseOut; break;
6515			case 'toggle': start = (layout == 0) ? caseIn : caseOut;
6516		}
6517		return this.parent(start[0], start[1]);
6518	},
6519
6520	slideIn: function(mode){
6521		return this.start('in', mode);
6522	},
6523
6524	slideOut: function(mode){
6525		return this.start('out', mode);
6526	},
6527
6528	hide: function(mode){
6529		this[mode || this.options.mode]();
6530		this.open = false;
6531		return this.set([-this.offset, 0]);
6532	},
6533
6534	show: function(mode){
6535		this[mode || this.options.mode]();
6536		this.open = true;
6537		return this.set([0, this.offset]);
6538	},
6539
6540	toggle: function(mode){
6541		return this.start('toggle', mode);
6542	}
6543
6544});
6545
6546Element.Properties.slide = {
6547
6548	set: function(options){
6549		this.get('slide').cancel().setOptions(options);
6550		return this;
6551	},
6552
6553	get: function(){
6554		var slide = this.retrieve('slide');
6555		if (!slide){
6556			slide = new Fx.Slide(this, {link: 'cancel'});
6557			this.store('slide', slide);
6558		}
6559		return slide;
6560	}
6561
6562};
6563
6564Element.implement({
6565
6566	slide: function(how, mode){
6567		how = how || 'toggle';
6568		var slide = this.get('slide'), toggle;
6569		switch (how){
6570			case 'hide': slide.hide(mode); break;
6571			case 'show': slide.show(mode); break;
6572			case 'toggle':
6573				var flag = this.retrieve('slide:flag', slide.open);
6574				slide[flag ? 'slideOut' : 'slideIn'](mode);
6575				this.store('slide:flag', !flag);
6576				toggle = true;
6577				break;
6578			default: slide.start(how, mode);
6579		}
6580		if (!toggle) this.eliminate('slide:flag');
6581		return this;
6582	}
6583
6584});
6585
6586/*
6587---
6588
6589script: Fx.SmoothScroll.js
6590
6591name: Fx.SmoothScroll
6592
6593description: Class for creating a smooth scrolling effect to all internal links on the page.
6594
6595license: MIT-style license
6596
6597authors:
6598  - Valerio Proietti
6599
6600requires:
6601  - Core/Slick.Finder
6602  - Fx.Scroll
6603
6604provides: [Fx.SmoothScroll]
6605
6606...
6607*/
6608
6609Fx.SmoothScroll = new Class({
6610
6611	Extends: Fx.Scroll,
6612
6613	options: {
6614		axes: ['x', 'y']
6615	},
6616
6617	initialize: function(options, context){
6618		context = context || document;
6619		this.doc = context.getDocument();
6620		this.parent(this.doc, options);
6621
6622		var win = context.getWindow(),
6623			location = win.location.href.match(/^[^#]*/)[0] + '#',
6624			links = $$(this.options.links || this.doc.links);
6625
6626		links.each(function(link){
6627			if (link.href.indexOf(location) != 0) return;
6628			var anchor = link.href.substr(location.length);
6629			if (anchor) this.useLink(link, anchor);
6630		}, this);
6631
6632		this.addEvent('complete', function(){
6633			win.location.hash = this.anchor;
6634			this.element.scrollTo(this.to[0], this.to[1]);
6635		}, true);
6636	},
6637
6638	useLink: function(link, anchor){
6639
6640		link.addEvent('click', function(event){
6641			var el = document.id(anchor) || this.doc.getElement('a[name=' + anchor + ']');
6642			if (!el) return;
6643
6644			event.preventDefault();
6645			this.toElement(el, this.options.axes).chain(function(){
6646				this.fireEvent('scrolledTo', [link, el]);
6647			}.bind(this));
6648
6649			this.anchor = anchor;
6650
6651		}.bind(this));
6652
6653		return this;
6654	}
6655});
6656
6657/*
6658---
6659
6660script: Fx.Sort.js
6661
6662name: Fx.Sort
6663
6664description: Defines Fx.Sort, a class that reorders lists with a transition.
6665
6666license: MIT-style license
6667
6668authors:
6669  - Aaron Newton
6670
6671requires:
6672  - Core/Element.Dimensions
6673  - Fx.Elements
6674  - Element.Measure
6675
6676provides: [Fx.Sort]
6677
6678...
6679*/
6680
6681Fx.Sort = new Class({
6682
6683	Extends: Fx.Elements,
6684
6685	options: {
6686		mode: 'vertical'
6687	},
6688
6689	initialize: function(elements, options){
6690		this.parent(elements, options);
6691		this.elements.each(function(el){
6692			if (el.getStyle('position') == 'static') el.setStyle('position', 'relative');
6693		});
6694		this.setDefaultOrder();
6695	},
6696
6697	setDefaultOrder: function(){
6698		this.currentOrder = this.elements.map(function(el, index){
6699			return index;
6700		});
6701	},
6702
6703	sort: function(){
6704		if (!this.check(arguments)) return this;
6705		var newOrder = Array.flatten(arguments);
6706
6707		var top = 0,
6708			left = 0,
6709			next = {},
6710			zero = {},
6711			vert = this.options.mode == 'vertical';
6712
6713		var current = this.elements.map(function(el, index){
6714			var size = el.getComputedSize({styles: ['border', 'padding', 'margin']});
6715			var val;
6716			if (vert){
6717				val = {
6718					top: top,
6719					margin: size['margin-top'],
6720					height: size.totalHeight
6721				};
6722				top += val.height - size['margin-top'];
6723			} else {
6724				val = {
6725					left: left,
6726					margin: size['margin-left'],
6727					width: size.totalWidth
6728				};
6729				left += val.width;
6730			}
6731			var plane = vert ? 'top' : 'left';
6732			zero[index] = {};
6733			var start = el.getStyle(plane).toInt();
6734			zero[index][plane] = start || 0;
6735			return val;
6736		}, this);
6737
6738		this.set(zero);
6739		newOrder = newOrder.map(function(i){ return i.toInt(); });
6740		if (newOrder.length != this.elements.length){
6741			this.currentOrder.each(function(index){
6742				if (!newOrder.contains(index)) newOrder.push(index);
6743			});
6744			if (newOrder.length > this.elements.length)
6745				newOrder.splice(this.elements.length-1, newOrder.length - this.elements.length);
6746		}
6747		var margin = 0;
6748		top = left = 0;
6749		newOrder.each(function(item){
6750			var newPos = {};
6751			if (vert){
6752				newPos.top = top - current[item].top - margin;
6753				top += current[item].height;
6754			} else {
6755				newPos.left = left - current[item].left;
6756				left += current[item].width;
6757			}
6758			margin = margin + current[item].margin;
6759			next[item]=newPos;
6760		}, this);
6761		var mapped = {};
6762		Array.clone(newOrder).sort().each(function(index){
6763			mapped[index] = next[index];
6764		});
6765		this.start(mapped);
6766		this.currentOrder = newOrder;
6767
6768		return this;
6769	},
6770
6771	rearrangeDOM: function(newOrder){
6772		newOrder = newOrder || this.currentOrder;
6773		var parent = this.elements[0].getParent();
6774		var rearranged = [];
6775		this.elements.setStyle('opacity', 0);
6776		//move each element and store the new default order
6777		newOrder.each(function(index){
6778			rearranged.push(this.elements[index].inject(parent).setStyles({
6779				top: 0,
6780				left: 0
6781			}));
6782		}, this);
6783		this.elements.setStyle('opacity', 1);
6784		this.elements = $$(rearranged);
6785		this.setDefaultOrder();
6786		return this;
6787	},
6788
6789	getDefaultOrder: function(){
6790		return this.elements.map(function(el, index){
6791			return index;
6792		});
6793	},
6794
6795	getCurrentOrder: function(){
6796		return this.currentOrder;
6797	},
6798
6799	forward: function(){
6800		return this.sort(this.getDefaultOrder());
6801	},
6802
6803	backward: function(){
6804		return this.sort(this.getDefaultOrder().reverse());
6805	},
6806
6807	reverse: function(){
6808		return this.sort(this.currentOrder.reverse());
6809	},
6810
6811	sortByElements: function(elements){
6812		return this.sort(elements.map(function(el){
6813			return this.elements.indexOf(el);
6814		}, this));
6815	},
6816
6817	swap: function(one, two){
6818		if (typeOf(one) == 'element') one = this.elements.indexOf(one);
6819		if (typeOf(two) == 'element') two = this.elements.indexOf(two);
6820
6821		var newOrder = Array.clone(this.currentOrder);
6822		newOrder[this.currentOrder.indexOf(one)] = two;
6823		newOrder[this.currentOrder.indexOf(two)] = one;
6824
6825		return this.sort(newOrder);
6826	}
6827
6828});
6829
6830/*
6831---
6832
6833script: Keyboard.js
6834
6835name: Keyboard
6836
6837description: KeyboardEvents used to intercept events on a class for keyboard and format modifiers in a specific order so as to make alt+shift+c the same as shift+alt+c.
6838
6839license: MIT-style license
6840
6841authors:
6842  - Perrin Westrich
6843  - Aaron Newton
6844  - Scott Kyle
6845
6846requires:
6847  - Core/Events
6848  - Core/Options
6849  - Core/Element.Event
6850  - Element.Event.Pseudos.Keys
6851
6852provides: [Keyboard]
6853
6854...
6855*/
6856
6857(function(){
6858
6859var Keyboard = this.Keyboard = new Class({
6860
6861	Extends: Events,
6862
6863	Implements: [Options],
6864
6865	options: {/*
6866		onActivate: function(){},
6867		onDeactivate: function(){},*/
6868		defaultEventType: 'keydown',
6869		active: false,
6870		manager: null,
6871		events: {},
6872		nonParsedEvents: ['activate', 'deactivate', 'onactivate', 'ondeactivate', 'changed', 'onchanged']
6873	},
6874
6875	initialize: function(options){
6876		if (options && options.manager){
6877			this._manager = options.manager;
6878			delete options.manager;
6879		}
6880		this.setOptions(options);
6881		this._setup();
6882	},
6883
6884	addEvent: function(type, fn, internal){
6885		return this.parent(Keyboard.parse(type, this.options.defaultEventType, this.options.nonParsedEvents), fn, internal);
6886	},
6887
6888	removeEvent: function(type, fn){
6889		return this.parent(Keyboard.parse(type, this.options.defaultEventType, this.options.nonParsedEvents), fn);
6890	},
6891
6892	toggleActive: function(){
6893		return this[this.isActive() ? 'deactivate' : 'activate']();
6894	},
6895
6896	activate: function(instance){
6897		if (instance){
6898			if (instance.isActive()) return this;
6899			//if we're stealing focus, store the last keyboard to have it so the relinquish command works
6900			if (this._activeKB && instance != this._activeKB){
6901				this.previous = this._activeKB;
6902				this.previous.fireEvent('deactivate');
6903			}
6904			//if we're enabling a child, assign it so that events are now passed to it
6905			this._activeKB = instance.fireEvent('activate');
6906			Keyboard.manager.fireEvent('changed');
6907		} else if (this._manager){
6908			//else we're enabling ourselves, we must ask our parent to do it for us
6909			this._manager.activate(this);
6910		}
6911		return this;
6912	},
6913
6914	isActive: function(){
6915		return this._manager ? (this._manager._activeKB == this) : (Keyboard.manager == this);
6916	},
6917
6918	deactivate: function(instance){
6919		if (instance){
6920			if (instance === this._activeKB){
6921				this._activeKB = null;
6922				instance.fireEvent('deactivate');
6923				Keyboard.manager.fireEvent('changed');
6924			}
6925		} else if (this._manager){
6926			this._manager.deactivate(this);
6927		}
6928		return this;
6929	},
6930
6931	relinquish: function(){
6932		if (this.isActive() && this._manager && this._manager.previous) this._manager.activate(this._manager.previous);
6933		else this.deactivate();
6934		return this;
6935	},
6936
6937	//management logic
6938	manage: function(instance){
6939		if (instance._manager) instance._manager.drop(instance);
6940		this._instances.push(instance);
6941		instance._manager = this;
6942		if (!this._activeKB) this.activate(instance);
6943		return this;
6944	},
6945
6946	drop: function(instance){
6947		instance.relinquish();
6948		this._instances.erase(instance);
6949		if (this._activeKB == instance){
6950			if (this.previous && this._instances.contains(this.previous)) this.activate(this.previous);
6951			else this._activeKB = this._instances[0];
6952		}
6953		return this;
6954	},
6955
6956	trace: function(){
6957		Keyboard.trace(this);
6958	},
6959
6960	each: function(fn){
6961		Keyboard.each(this, fn);
6962	},
6963
6964	/*
6965		PRIVATE METHODS
6966	*/
6967
6968	_instances: [],
6969
6970	_disable: function(instance){
6971		if (this._activeKB == instance) this._activeKB = null;
6972	},
6973
6974	_setup: function(){
6975		this.addEvents(this.options.events);
6976		//if this is the root manager, nothing manages it
6977		if (Keyboard.manager && !this._manager) Keyboard.manager.manage(this);
6978		if (this.options.active) this.activate();
6979		else this.relinquish();
6980	},
6981
6982	_handle: function(event, type){
6983		//Keyboard.stop(event) prevents key propagation
6984		if (event.preventKeyboardPropagation) return;
6985
6986		var bubbles = !!this._manager;
6987		if (bubbles && this._activeKB){
6988			this._activeKB._handle(event, type);
6989			if (event.preventKeyboardPropagation) return;
6990		}
6991		this.fireEvent(type, event);
6992
6993		if (!bubbles && this._activeKB) this._activeKB._handle(event, type);
6994	}
6995
6996});
6997
6998var parsed = {};
6999var modifiers = ['shift', 'control', 'alt', 'meta'];
7000var regex = /^(?:shift|control|ctrl|alt|meta)$/;
7001
7002Keyboard.parse = function(type, eventType, ignore){
7003	if (ignore && ignore.contains(type.toLowerCase())) return type;
7004
7005	type = type.toLowerCase().replace(/^(keyup|keydown):/, function($0, $1){
7006		eventType = $1;
7007		return '';
7008	});
7009
7010	if (!parsed[type]){
7011		if (type != '+'){
7012			var key, mods = {};
7013			type.split('+').each(function(part){
7014				if (regex.test(part)) mods[part] = true;
7015				else key = part;
7016			});
7017
7018			mods.control = mods.control || mods.ctrl; // allow both control and ctrl
7019
7020			var keys = [];
7021			modifiers.each(function(mod){
7022				if (mods[mod]) keys.push(mod);
7023			});
7024
7025			if (key) keys.push(key);
7026			parsed[type] = keys.join('+');
7027		} else {
7028			parsed[type] = type;
7029		}
7030	}
7031
7032	return eventType + ':keys(' + parsed[type] + ')';
7033};
7034
7035Keyboard.each = function(keyboard, fn){
7036	var current = keyboard || Keyboard.manager;
7037	while (current){
7038		fn(current);
7039		current = current._activeKB;
7040	}
7041};
7042
7043Keyboard.stop = function(event){
7044	event.preventKeyboardPropagation = true;
7045};
7046
7047Keyboard.manager = new Keyboard({
7048	active: true
7049});
7050
7051Keyboard.trace = function(keyboard){
7052	keyboard = keyboard || Keyboard.manager;
7053	var hasConsole = window.console && console.log;
7054	if (hasConsole) console.log('the following items have focus: ');
7055	Keyboard.each(keyboard, function(current){
7056		if (hasConsole) console.log(document.id(current.widget) || current.wiget || current);
7057	});
7058};
7059
7060var handler = function(event){
7061	var keys = [];
7062	modifiers.each(function(mod){
7063		if (event[mod]) keys.push(mod);
7064	});
7065
7066	if (!regex.test(event.key)) keys.push(event.key);
7067	Keyboard.manager._handle(event, event.type + ':keys(' + keys.join('+') + ')');
7068};
7069
7070document.addEvents({
7071	'keyup': handler,
7072	'keydown': handler
7073});
7074
7075})();
7076
7077/*
7078---
7079
7080script: Keyboard.Extras.js
7081
7082name: Keyboard.Extras
7083
7084description: Enhances Keyboard by adding the ability to name and describe keyboard shortcuts, and the ability to grab shortcuts by name and bind the shortcut to different keys.
7085
7086license: MIT-style license
7087
7088authors:
7089  - Perrin Westrich
7090
7091requires:
7092  - Keyboard
7093  - MooTools.More
7094
7095provides: [Keyboard.Extras]
7096
7097...
7098*/
7099Keyboard.prototype.options.nonParsedEvents.combine(['rebound', 'onrebound']);
7100
7101Keyboard.implement({
7102
7103	/*
7104		shortcut should be in the format of:
7105		{
7106			'keys': 'shift+s', // the default to add as an event.
7107			'description': 'blah blah blah', // a brief description of the functionality.
7108			'handler': function(){} // the event handler to run when keys are pressed.
7109		}
7110	*/
7111	addShortcut: function(name, shortcut){
7112		this._shortcuts = this._shortcuts || [];
7113		this._shortcutIndex = this._shortcutIndex || {};
7114
7115		shortcut.getKeyboard = Function.convert(this);
7116		shortcut.name = name;
7117		this._shortcutIndex[name] = shortcut;
7118		this._shortcuts.push(shortcut);
7119		if (shortcut.keys) this.addEvent(shortcut.keys, shortcut.handler);
7120		return this;
7121	},
7122
7123	addShortcuts: function(obj){
7124		for (var name in obj) this.addShortcut(name, obj[name]);
7125		return this;
7126	},
7127
7128	removeShortcut: function(name){
7129		var shortcut = this.getShortcut(name);
7130		if (shortcut && shortcut.keys){
7131			this.removeEvent(shortcut.keys, shortcut.handler);
7132			delete this._shortcutIndex[name];
7133			this._shortcuts.erase(shortcut);
7134		}
7135		return this;
7136	},
7137
7138	removeShortcuts: function(names){
7139		names.each(this.removeShortcut, this);
7140		return this;
7141	},
7142
7143	getShortcuts: function(){
7144		return this._shortcuts || [];
7145	},
7146
7147	getShortcut: function(name){
7148		return (this._shortcutIndex || {})[name];
7149	}
7150
7151});
7152
7153Keyboard.rebind = function(newKeys, shortcuts){
7154	Array.convert(shortcuts).each(function(shortcut){
7155		shortcut.getKeyboard().removeEvent(shortcut.keys, shortcut.handler);
7156		shortcut.getKeyboard().addEvent(newKeys, shortcut.handler);
7157		shortcut.keys = newKeys;
7158		shortcut.getKeyboard().fireEvent('rebound');
7159	});
7160};
7161
7162
7163Keyboard.getActiveShortcuts = function(keyboard){
7164	var activeKBS = [], activeSCS = [];
7165	Keyboard.each(keyboard, [].push.bind(activeKBS));
7166	activeKBS.each(function(kb){ activeSCS.extend(kb.getShortcuts()); });
7167	return activeSCS;
7168};
7169
7170Keyboard.getShortcut = function(name, keyboard, opts){
7171	opts = opts || {};
7172	var shortcuts = opts.many ? [] : null,
7173		set = opts.many ? function(kb){
7174			var shortcut = kb.getShortcut(name);
7175			if (shortcut) shortcuts.push(shortcut);
7176		} : function(kb){
7177			if (!shortcuts) shortcuts = kb.getShortcut(name);
7178		};
7179	Keyboard.each(keyboard, set);
7180	return shortcuts;
7181};
7182
7183Keyboard.getShortcuts = function(name, keyboard){
7184	return Keyboard.getShortcut(name, keyboard, { many: true });
7185};
7186
7187/*
7188---
7189
7190script: HtmlTable.js
7191
7192name: HtmlTable
7193
7194description: Builds table elements with methods to add rows.
7195
7196license: MIT-style license
7197
7198authors:
7199  - Aaron Newton
7200
7201requires:
7202  - Core/Options
7203  - Core/Events
7204  - Class.Occlude
7205
7206provides: [HtmlTable]
7207
7208...
7209*/
7210(function(){
7211
7212var HtmlTable = this.HtmlTable = new Class({
7213
7214	Implements: [Options, Events, Class.Occlude],
7215
7216	options: {
7217		properties: {
7218			cellpadding: 0,
7219			cellspacing: 0,
7220			border: 0
7221		},
7222		rows: [],
7223		headers: [],
7224		footers: []
7225	},
7226
7227	property: 'HtmlTable',
7228
7229	initialize: function(){
7230		var params = Array.link(arguments, {options: Type.isObject, table: Type.isElement, id: Type.isString});
7231		this.setOptions(params.options);
7232		if (!params.table && params.id) params.table = document.id(params.id);
7233		this.element = params.table || new Element('table', this.options.properties);
7234		if (this.occlude()) return this.occluded;
7235		this.build();
7236	},
7237
7238	build: function(){
7239		this.element.store('HtmlTable', this);
7240
7241		this.body = document.id(this.element.tBodies[0]) || new Element('tbody').inject(this.element);
7242		$$(this.body.rows);
7243
7244		if (this.options.headers.length) this.setHeaders(this.options.headers);
7245		else this.thead = document.id(this.element.tHead);
7246
7247		if (this.thead) this.head = this.getHead();
7248		if (this.options.footers.length) this.setFooters(this.options.footers);
7249
7250		this.tfoot = document.id(this.element.tFoot);
7251		if (this.tfoot) this.foot = document.id(this.tfoot.rows[0]);
7252
7253		this.options.rows.each(function(row){
7254			this.push(row);
7255		}, this);
7256	},
7257
7258	toElement: function(){
7259		return this.element;
7260	},
7261
7262	empty: function(){
7263		this.body.empty();
7264		return this;
7265	},
7266
7267	set: function(what, items){
7268		var target = (what == 'headers') ? 'tHead' : 'tFoot',
7269			lower = target.toLowerCase();
7270
7271		this[lower] = (document.id(this.element[target]) || new Element(lower).inject(this.element, 'top')).empty();
7272		var data = this.push(items, {}, this[lower], what == 'headers' ? 'th' : 'td');
7273
7274		if (what == 'headers') this.head = this.getHead();
7275		else this.foot = this.getHead();
7276
7277		return data;
7278	},
7279
7280	getHead: function(){
7281		var rows = this.thead.rows;
7282		return rows.length > 1 ? $$(rows) : rows.length ? document.id(rows[0]) : false;
7283	},
7284
7285	setHeaders: function(headers){
7286		this.set('headers', headers);
7287		return this;
7288	},
7289
7290	setFooters: function(footers){
7291		this.set('footers', footers);
7292		return this;
7293	},
7294
7295	update: function(tr, row, tag){
7296		var tds = tr.getChildren(tag || 'td'), last = tds.length - 1;
7297
7298		row.each(function(data, index){
7299			var td = tds[index] || new Element(tag || 'td').inject(tr),
7300				content = ((data && Object.prototype.hasOwnProperty.call(data, 'content')) ? data.content : '') || data,
7301				type = typeOf(content);
7302
7303			if (data && Object.prototype.hasOwnProperty.call(data, 'properties')) td.set(data.properties);
7304			if (/(element(s?)|array|collection)/.test(type)) td.empty().adopt(content);
7305			else td.set('html', content);
7306
7307			if (index > last) tds.push(td);
7308			else tds[index] = td;
7309		});
7310
7311		return {
7312			tr: tr,
7313			tds: tds
7314		};
7315	},
7316
7317	push: function(row, rowProperties, target, tag, where){
7318		if (typeOf(row) == 'element' && row.get('tag') == 'tr'){
7319			row.inject(target || this.body, where);
7320			return {
7321				tr: row,
7322				tds: row.getChildren('td')
7323			};
7324		}
7325		return this.update(new Element('tr', rowProperties).inject(target || this.body, where), row, tag);
7326	},
7327
7328	pushMany: function(rows, rowProperties, target, tag, where){
7329		return rows.map(function(row){
7330			return this.push(row, rowProperties, target, tag, where);
7331		}, this);
7332	}
7333
7334});
7335
7336})();
7337
7338
7339['adopt', 'inject', 'wraps', 'grab', 'replaces', 'dispose'].each(function(method){
7340	HtmlTable.implement(method, function(){
7341		this.element[method].apply(this.element, arguments);
7342		return this;
7343	});
7344});
7345
7346
7347
7348/*
7349---
7350
7351script: HtmlTable.Select.js
7352
7353name: HtmlTable.Select
7354
7355description: Builds a stripy, sortable table with methods to add rows. Rows can be selected with the mouse or keyboard navigation.
7356
7357license: MIT-style license
7358
7359authors:
7360  - Harald Kirschner
7361  - Aaron Newton
7362
7363requires:
7364  - Keyboard
7365  - Keyboard.Extras
7366  - HtmlTable
7367  - Class.refactor
7368  - Element.Delegation.Pseudo
7369  - Element.Shortcuts
7370
7371provides: [HtmlTable.Select]
7372
7373...
7374*/
7375
7376HtmlTable = Class.refactor(HtmlTable, {
7377
7378	options: {
7379		/*onRowFocus: function(){},
7380		onRowUnfocus: function(){},*/
7381		useKeyboard: true,
7382		classRowSelected: 'table-tr-selected',
7383		classRowHovered: 'table-tr-hovered',
7384		classSelectable: 'table-selectable',
7385		shiftForMultiSelect: true,
7386		allowMultiSelect: true,
7387		selectable: false,
7388		selectHiddenRows: false
7389	},
7390
7391	initialize: function(){
7392		this.previous.apply(this, arguments);
7393		if (this.occluded) return this.occluded;
7394
7395		this.selectedRows = new Elements();
7396
7397		if (!this.bound) this.bound = {};
7398		this.bound.mouseleave = this.mouseleave.bind(this);
7399		this.bound.clickRow = this.clickRow.bind(this);
7400		this.bound.activateKeyboard = function(){
7401			if (this.keyboard && this.selectEnabled) this.keyboard.activate();
7402		}.bind(this);
7403
7404		if (this.options.selectable) this.enableSelect();
7405	},
7406
7407	empty: function(){
7408		if (this.body.rows.length) this.selectNone();
7409		return this.previous();
7410	},
7411
7412	enableSelect: function(){
7413		this.selectEnabled = true;
7414		this.attachSelects();
7415		this.element.addClass(this.options.classSelectable);
7416		return this;
7417	},
7418
7419	disableSelect: function(){
7420		this.selectEnabled = false;
7421		this.attachSelects(false);
7422		this.element.removeClass(this.options.classSelectable);
7423		return this;
7424	},
7425
7426	push: function(){
7427		var ret = this.previous.apply(this, arguments);
7428		this.updateSelects();
7429		return ret;
7430	},
7431
7432	toggleRow: function(row){
7433		return this[(this.isSelected(row) ? 'de' : '') + 'selectRow'](row);
7434	},
7435
7436	selectRow: function(row, _nocheck){
7437		//private variable _nocheck: boolean whether or not to confirm the row is in the table body
7438		//added here for optimization when selecting ranges
7439		if (this.isSelected(row) || (!_nocheck && !this.body.getChildren().contains(row))) return;
7440		if (!this.options.allowMultiSelect) this.selectNone();
7441
7442		if (!this.isSelected(row)){
7443			this.selectedRows.push(row);
7444			row.addClass(this.options.classRowSelected);
7445			this.fireEvent('rowFocus', [row, this.selectedRows]);
7446			this.fireEvent('stateChanged');
7447		}
7448
7449		this.focused = row;
7450		document.clearSelection();
7451
7452		return this;
7453	},
7454
7455	isSelected: function(row){
7456		return this.selectedRows.contains(row);
7457	},
7458
7459	getSelected: function(){
7460		return this.selectedRows;
7461	},
7462
7463	serialize: function(){
7464		var previousSerialization = this.previous.apply(this, arguments) || {};
7465		if (this.options.selectable){
7466			previousSerialization.selectedRows = this.selectedRows.map(function(row){
7467				return Array.indexOf(this.body.rows, row);
7468			}.bind(this));
7469		}
7470		return previousSerialization;
7471	},
7472
7473	restore: function(tableState){
7474		if (this.options.selectable && tableState.selectedRows){
7475			tableState.selectedRows.each(function(index){
7476				this.selectRow(this.body.rows[index]);
7477			}.bind(this));
7478		}
7479		this.previous.apply(this, arguments);
7480	},
7481
7482	deselectRow: function(row, _nocheck){
7483		if (!this.isSelected(row) || (!_nocheck && !this.body.getChildren().contains(row))) return;
7484
7485		this.selectedRows = new Elements(Array.convert(this.selectedRows).erase(row));
7486		row.removeClass(this.options.classRowSelected);
7487		this.fireEvent('rowUnfocus', [row, this.selectedRows]);
7488		this.fireEvent('stateChanged');
7489		return this;
7490	},
7491
7492	selectAll: function(selectNone){
7493		if (!selectNone && !this.options.allowMultiSelect) return;
7494		this.selectRange(0, this.body.rows.length, selectNone);
7495		return this;
7496	},
7497
7498	selectNone: function(){
7499		return this.selectAll(true);
7500	},
7501
7502	selectRange: function(startRow, endRow, _deselect){
7503		if (!this.options.allowMultiSelect && !_deselect) return;
7504		var method = _deselect ? 'deselectRow' : 'selectRow',
7505			rows = Array.clone(this.body.rows);
7506
7507		if (typeOf(startRow) == 'element') startRow = rows.indexOf(startRow);
7508		if (typeOf(endRow) == 'element') endRow = rows.indexOf(endRow);
7509		endRow = endRow < rows.length - 1 ? endRow : rows.length - 1;
7510
7511		if (endRow < startRow){
7512			var tmp = startRow;
7513			startRow = endRow;
7514			endRow = tmp;
7515		}
7516
7517		for (var i = startRow; i <= endRow; i++){
7518			if (this.options.selectHiddenRows || rows[i].isDisplayed()) this[method](rows[i], true);
7519		}
7520
7521		return this;
7522	},
7523
7524	deselectRange: function(startRow, endRow){
7525		this.selectRange(startRow, endRow, true);
7526	},
7527
7528/*
7529	Private methods:
7530*/
7531
7532	enterRow: function(row){
7533		if (this.hovered) this.hovered = this.leaveRow(this.hovered);
7534		this.hovered = row.addClass(this.options.classRowHovered);
7535	},
7536
7537	leaveRow: function(row){
7538		row.removeClass(this.options.classRowHovered);
7539	},
7540
7541	updateSelects: function(){
7542		Array.each(this.body.rows, function(row){
7543			var binders = row.retrieve('binders');
7544			if (!binders && !this.selectEnabled) return;
7545			if (!binders){
7546				binders = {
7547					mouseenter: this.enterRow.pass([row], this),
7548					mouseleave: this.leaveRow.pass([row], this)
7549				};
7550				row.store('binders', binders);
7551			}
7552			if (this.selectEnabled) row.addEvents(binders);
7553			else row.removeEvents(binders);
7554		}, this);
7555	},
7556
7557	shiftFocus: function(offset, event){
7558		if (!this.focused) return this.selectRow(this.body.rows[0], event);
7559		var to = this.getRowByOffset(offset, this.options.selectHiddenRows);
7560		if (to === null || this.focused == this.body.rows[to]) return this;
7561		this.toggleRow(this.body.rows[to], event);
7562	},
7563
7564	clickRow: function(event, row){
7565		var selecting = (event.shift || event.meta || event.control) && this.options.shiftForMultiSelect;
7566		if (!selecting && !(event.rightClick && this.isSelected(row) && this.options.allowMultiSelect)) this.selectNone();
7567
7568		if (event.rightClick) this.selectRow(row);
7569		else this.toggleRow(row);
7570
7571		if (event.shift){
7572			this.selectRange(this.rangeStart || this.body.rows[0], row, this.rangeStart ? !this.isSelected(row) : true);
7573			this.focused = row;
7574		}
7575		this.rangeStart = row;
7576	},
7577
7578	getRowByOffset: function(offset, includeHiddenRows){
7579		if (!this.focused) return 0;
7580		var index = Array.indexOf(this.body.rows, this.focused);
7581		if ((index == 0 && offset < 0) || (index == this.body.rows.length -1 && offset > 0)) return null;
7582		if (includeHiddenRows){
7583			index += offset;
7584		} else {
7585			var limit = 0,
7586				count = 0;
7587			if (offset > 0){
7588				while (count < offset && index < this.body.rows.length -1){
7589					if (this.body.rows[++index].isDisplayed()) count++;
7590				}
7591			} else {
7592				while (count > offset && index > 0){
7593					if (this.body.rows[--index].isDisplayed()) count--;
7594				}
7595			}
7596		}
7597		return index;
7598	},
7599
7600	attachSelects: function(attach){
7601		attach = attach != null ? attach : true;
7602
7603		var method = attach ? 'addEvents' : 'removeEvents';
7604		this.element[method]({
7605			mouseleave: this.bound.mouseleave,
7606			click: this.bound.activateKeyboard
7607		});
7608
7609		this.body[method]({
7610			'click:relay(tr)': this.bound.clickRow,
7611			'contextmenu:relay(tr)': this.bound.clickRow
7612		});
7613
7614		if (this.options.useKeyboard || this.keyboard){
7615			if (!this.keyboard) this.keyboard = new Keyboard();
7616			if (!this.selectKeysDefined){
7617				this.selectKeysDefined = true;
7618				var timer, held;
7619
7620				var move = function(offset){
7621					var mover = function(e){
7622						clearTimeout(timer);
7623						e.preventDefault();
7624						var to = this.body.rows[this.getRowByOffset(offset, this.options.selectHiddenRows)];
7625						if (e.shift && to && this.isSelected(to)){
7626							this.deselectRow(this.focused);
7627							this.focused = to;
7628						} else {
7629							if (to && (!this.options.allowMultiSelect || !e.shift)){
7630								this.selectNone();
7631							}
7632							this.shiftFocus(offset, e);
7633						}
7634
7635						if (held){
7636							timer = mover.delay(100, this, e);
7637						} else {
7638							timer = (function(){
7639								held = true;
7640								mover(e);
7641							}).delay(400);
7642						}
7643					}.bind(this);
7644					return mover;
7645				}.bind(this);
7646
7647				var clear = function(){
7648					clearTimeout(timer);
7649					held = false;
7650				};
7651
7652				this.keyboard.addEvents({
7653					'keydown:shift+up': move(-1),
7654					'keydown:shift+down': move(1),
7655					'keyup:shift+up': clear,
7656					'keyup:shift+down': clear,
7657					'keyup:up': clear,
7658					'keyup:down': clear
7659				});
7660
7661				var shiftHint = '';
7662				if (this.options.allowMultiSelect && this.options.shiftForMultiSelect && this.options.useKeyboard){
7663					shiftHint = ' (Shift multi-selects).';
7664				}
7665
7666				this.keyboard.addShortcuts({
7667					'Select Previous Row': {
7668						keys: 'up',
7669						shortcut: 'up arrow',
7670						handler: move(-1),
7671						description: 'Select the previous row in the table.' + shiftHint
7672					},
7673					'Select Next Row': {
7674						keys: 'down',
7675						shortcut: 'down arrow',
7676						handler: move(1),
7677						description: 'Select the next row in the table.' + shiftHint
7678					}
7679				});
7680
7681			}
7682			this.keyboard[attach ? 'activate' : 'deactivate']();
7683		}
7684		this.updateSelects();
7685	},
7686
7687	mouseleave: function(){
7688		if (this.hovered) this.leaveRow(this.hovered);
7689	}
7690
7691});
7692
7693/*
7694---
7695
7696script: HtmlTable.Sort.js
7697
7698name: HtmlTable.Sort
7699
7700description: Builds a stripy, sortable table with methods to add rows.
7701
7702license: MIT-style license
7703
7704authors:
7705  - Harald Kirschner
7706  - Aaron Newton
7707  - Jacob Thornton
7708
7709requires:
7710  - Core/Hash
7711  - HtmlTable
7712  - Class.refactor
7713  - Element.Delegation.Pseudo
7714  - String.Extras
7715  - Date
7716
7717provides: [HtmlTable.Sort]
7718
7719...
7720*/
7721(function(){
7722
7723var readOnlyNess = document.createElement('table');
7724try {
7725	readOnlyNess.innerHTML = '<tr><td></td></tr>';
7726	readOnlyNess = readOnlyNess.childNodes.length === 0;
7727} catch (e){
7728	readOnlyNess = true;
7729}
7730
7731HtmlTable = Class.refactor(HtmlTable, {
7732
7733	options: {/*
7734		onSort: function(){}, */
7735		sortIndex: 0,
7736		sortReverse: false,
7737		parsers: [],
7738		defaultParser: 'string',
7739		classSortable: 'table-sortable',
7740		classHeadSort: 'table-th-sort',
7741		classHeadSortRev: 'table-th-sort-rev',
7742		classNoSort: 'table-th-nosort',
7743		classGroupHead: 'table-tr-group-head',
7744		classGroup: 'table-tr-group',
7745		classCellSort: 'table-td-sort',
7746		classSortSpan: 'table-th-sort-span',
7747		sortable: false,
7748		thSelector: 'th'
7749	},
7750
7751	initialize: function(){
7752		this.previous.apply(this, arguments);
7753		if (this.occluded) return this.occluded;
7754		this.sorted = {index: null, dir: 1};
7755		if (!this.bound) this.bound = {};
7756		this.bound.headClick = this.headClick.bind(this);
7757		this.sortSpans = new Elements();
7758		if (this.options.sortable){
7759			this.enableSort();
7760			if (this.options.sortIndex != null) this.sort(this.options.sortIndex, this.options.sortReverse);
7761		}
7762	},
7763
7764	attachSorts: function(attach){
7765		this.detachSorts();
7766		if (attach !== false) this.element.addEvent('click:relay(' + this.options.thSelector + ')', this.bound.headClick);
7767	},
7768
7769	detachSorts: function(){
7770		this.element.removeEvents('click:relay(' + this.options.thSelector + ')');
7771	},
7772
7773	setHeaders: function(){
7774		this.previous.apply(this, arguments);
7775		if (this.sortable) this.setParsers();
7776	},
7777
7778	setParsers: function(){
7779		this.parsers = this.detectParsers();
7780	},
7781
7782	detectParsers: function(){
7783		return this.head && this.head.getElements(this.options.thSelector).flatten().map(this.detectParser, this);
7784	},
7785
7786	detectParser: function(cell, index){
7787		if (cell.hasClass(this.options.classNoSort) || cell.retrieve('htmltable-parser')) return cell.retrieve('htmltable-parser');
7788		var thDiv = new Element('div');
7789		thDiv.adopt(cell.childNodes).inject(cell);
7790		var sortSpan = new Element('span', {'class': this.options.classSortSpan}).inject(thDiv, 'top');
7791		this.sortSpans.push(sortSpan);
7792		var parser = this.options.parsers[index],
7793			rows = this.body.rows,
7794			cancel;
7795		switch (typeOf(parser)){
7796			case 'function': parser = {convert: parser}; cancel = true; break;
7797			case 'string': parser = parser; cancel = true; break;
7798		}
7799		if (!cancel){
7800			HtmlTable.ParserPriority.some(function(parserName){
7801				var current = HtmlTable.Parsers[parserName],
7802					match = current.match;
7803				if (!match) return false;
7804				for (var i = 0, j = rows.length; i < j; i++){
7805					var cell = document.id(rows[i].cells[index]),
7806						text = cell ? cell.get('html').clean() : '';
7807					if (text && match.test(text)){
7808						parser = current;
7809						return true;
7810					}
7811				}
7812			});
7813		}
7814		if (!parser) parser = this.options.defaultParser;
7815		cell.store('htmltable-parser', parser);
7816		return parser;
7817	},
7818
7819	headClick: function(event, el){
7820		if (!this.head || el.hasClass(this.options.classNoSort)) return;
7821		return this.sort(Array.indexOf(this.head.getElements(this.options.thSelector).flatten(), el) % this.body.rows[0].cells.length);
7822	},
7823
7824	serialize: function(){
7825		var previousSerialization = this.previous.apply(this, arguments) || {};
7826		if (this.options.sortable){
7827			previousSerialization.sortIndex = this.sorted.index;
7828			previousSerialization.sortReverse = this.sorted.reverse;
7829		}
7830		return previousSerialization;
7831	},
7832
7833	restore: function(tableState){
7834		if (this.options.sortable && tableState.sortIndex){
7835			this.sort(tableState.sortIndex, tableState.sortReverse);
7836		}
7837		this.previous.apply(this, arguments);
7838	},
7839
7840	setSortedState: function(index, reverse){
7841		if (reverse != null) this.sorted.reverse = reverse;
7842		else if (this.sorted.index == index) this.sorted.reverse = !this.sorted.reverse;
7843		else this.sorted.reverse = this.sorted.index == null;
7844
7845		if (index != null) this.sorted.index = index;
7846	},
7847
7848	setHeadSort: function(sorted){
7849		var head = $$(!this.head.length ? this.head.cells[this.sorted.index] : this.head.map(function(row){
7850			return row.getElements(this.options.thSelector)[this.sorted.index];
7851		}, this).clean());
7852		if (!head.length) return;
7853		if (sorted){
7854			head.addClass(this.options.classHeadSort);
7855			if (this.sorted.reverse) head.addClass(this.options.classHeadSortRev);
7856			else head.removeClass(this.options.classHeadSortRev);
7857		} else {
7858			head.removeClass(this.options.classHeadSort).removeClass(this.options.classHeadSortRev);
7859		}
7860	},
7861
7862	setRowSort: function(data, pre){
7863		var count = data.length,
7864			body = this.body,
7865			group,
7866			rowIndex;
7867
7868		while (count){
7869			var item = data[--count],
7870				position = item.position,
7871				row = body.rows[position];
7872
7873			if (row.disabled) continue;
7874			if (!pre){
7875				group = this.setGroupSort(group, row, item);
7876				this.setRowStyle(row, count);
7877			}
7878			body.appendChild(row);
7879
7880			for (rowIndex = 0; rowIndex < count; rowIndex++){
7881				if (data[rowIndex].position > position) data[rowIndex].position--;
7882			}
7883		}
7884	},
7885
7886	setRowStyle: function(row, i){
7887		this.previous(row, i);
7888		row.cells[this.sorted.index].addClass(this.options.classCellSort);
7889	},
7890
7891	setGroupSort: function(group, row, item){
7892		if (group == item.value) row.removeClass(this.options.classGroupHead).addClass(this.options.classGroup);
7893		else row.removeClass(this.options.classGroup).addClass(this.options.classGroupHead);
7894		return item.value;
7895	},
7896
7897	getParser: function(){
7898		var parser = this.parsers[this.sorted.index];
7899		return typeOf(parser) == 'string' ? HtmlTable.Parsers[parser] : parser;
7900	},
7901
7902	sort: function(index, reverse, pre, sortFunction){
7903		if (!this.head) return;
7904
7905		if (!pre){
7906			this.clearSort();
7907			this.setSortedState(index, reverse);
7908			this.setHeadSort(true);
7909		}
7910
7911		var parser = this.getParser();
7912		if (!parser) return;
7913
7914		var rel;
7915		if (!readOnlyNess){
7916			rel = this.body.getParent();
7917			this.body.dispose();
7918		}
7919
7920		var data = this.parseData(parser).sort(sortFunction ? sortFunction : function(a, b){
7921			if (a.value === b.value) return 0;
7922			return a.value > b.value ? 1 : -1;
7923		});
7924
7925		var reversed = this.sorted.reverse == (parser == HtmlTable.Parsers['input-checked']);
7926		if (reversed) data.reverse(true);
7927		this.setRowSort(data, pre);
7928
7929		if (rel) rel.grab(this.body);
7930		this.fireEvent('stateChanged');
7931		return this.fireEvent('sort', [this.body, this.sorted.index, reversed ? 'asc' : 'desc']);
7932	},
7933
7934	parseData: function(parser){
7935		return Array.map(this.body.rows, function(row, i){
7936			var value = parser.convert.call(document.id(row.cells[this.sorted.index]));
7937			return {
7938				position: i,
7939				value: value
7940			};
7941		}, this);
7942	},
7943
7944	clearSort: function(){
7945		this.setHeadSort(false);
7946		this.body.getElements('td').removeClass(this.options.classCellSort);
7947	},
7948
7949	reSort: function(){
7950		if (this.sortable) this.sort.call(this, this.sorted.index, this.sorted.reverse);
7951		return this;
7952	},
7953
7954	enableSort: function(){
7955		this.element.addClass(this.options.classSortable);
7956		this.attachSorts(true);
7957		this.setParsers();
7958		this.sortable = true;
7959		return this;
7960	},
7961
7962	disableSort: function(){
7963		this.element.removeClass(this.options.classSortable);
7964		this.attachSorts(false);
7965		this.sortSpans.each(function(span){
7966			span.destroy();
7967		});
7968		this.sortSpans.empty();
7969		this.sortable = false;
7970		return this;
7971	}
7972
7973});
7974
7975HtmlTable.ParserPriority = ['date', 'input-checked', 'input-value', 'float', 'number'];
7976
7977HtmlTable.Parsers = {
7978
7979	'date': {
7980		match: /^\d{2}[-\/ ]\d{2}[-\/ ]\d{2,4}$/,
7981		convert: function(){
7982			var d = Date.parse(this.get('text').stripTags());
7983			return (typeOf(d) == 'date') ? d.format('db') : '';
7984		},
7985		type: 'date'
7986	},
7987	'input-checked': {
7988		match: / type="(radio|checkbox)"/,
7989		convert: function(){
7990			return this.getElement('input').checked;
7991		}
7992	},
7993	'input-value': {
7994		match: /<input/,
7995		convert: function(){
7996			return this.getElement('input').value;
7997		}
7998	},
7999	'number': {
8000		match: /^\d+[^\d.,]*$/,
8001		convert: function(){
8002			return this.get('text').stripTags().toInt();
8003		},
8004		number: true
8005	},
8006	'numberLax': {
8007		match: /^[^\d]+\d+$/,
8008		convert: function(){
8009			return this.get('text').replace(/[^-?^0-9]/, '').stripTags().toInt();
8010		},
8011		number: true
8012	},
8013	'float': {
8014		match: /^[\d]+\.[\d]+/,
8015		convert: function(){
8016			return this.get('text').replace(/[^-?^\d.e]/, '').stripTags().toFloat();
8017		},
8018		number: true
8019	},
8020	'floatLax': {
8021		match: /^[^\d]+[\d]+\.[\d]+$/,
8022		convert: function(){
8023			return this.get('text').replace(/[^-?^\d.]/, '').stripTags().toFloat();
8024		},
8025		number: true
8026	},
8027	'string': {
8028		match: null,
8029		convert: function(){
8030			return this.get('text').stripTags().toLowerCase();
8031		}
8032	},
8033	'title': {
8034		match: null,
8035		convert: function(){
8036			return this.title;
8037		}
8038	}
8039
8040};
8041
8042
8043
8044HtmlTable.defineParsers = function(parsers){
8045	HtmlTable.Parsers = Object.append(HtmlTable.Parsers, parsers);
8046	for (var parser in parsers){
8047		HtmlTable.ParserPriority.unshift(parser);
8048	}
8049};
8050
8051})();
8052
8053
8054/*
8055---
8056
8057script: HtmlTable.Zebra.js
8058
8059name: HtmlTable.Zebra
8060
8061description: Builds a stripy table with methods to add rows.
8062
8063license: MIT-style license
8064
8065authors:
8066  - Harald Kirschner
8067  - Aaron Newton
8068
8069requires:
8070  - HtmlTable
8071  - Element.Shortcuts
8072  - Class.refactor
8073
8074provides: [HtmlTable.Zebra]
8075
8076...
8077*/
8078
8079HtmlTable = Class.refactor(HtmlTable, {
8080
8081	options: {
8082		classZebra: 'table-tr-odd',
8083		zebra: true,
8084		zebraOnlyVisibleRows: true
8085	},
8086
8087	initialize: function(){
8088		this.previous.apply(this, arguments);
8089		if (this.occluded) return this.occluded;
8090		if (this.options.zebra) this.updateZebras();
8091	},
8092
8093	updateZebras: function(){
8094		var index = 0;
8095		Array.each(this.body.rows, function(row){
8096			if (!this.options.zebraOnlyVisibleRows || row.isDisplayed()){
8097				this.zebra(row, index++);
8098			}
8099		}, this);
8100	},
8101
8102	setRowStyle: function(row, i){
8103		if (this.previous) this.previous(row, i);
8104		this.zebra(row, i);
8105	},
8106
8107	zebra: function(row, i){
8108		return row[((i % 2) ? 'remove' : 'add')+'Class'](this.options.classZebra);
8109	},
8110
8111	push: function(){
8112		var pushed = this.previous.apply(this, arguments);
8113		if (this.options.zebra) this.updateZebras();
8114		return pushed;
8115	}
8116
8117});
8118
8119/*
8120---
8121
8122script: Scroller.js
8123
8124name: Scroller
8125
8126description: Class which scrolls the contents of any Element (including the window) when the mouse reaches the Element's boundaries.
8127
8128license: MIT-style license
8129
8130authors:
8131  - Valerio Proietti
8132
8133requires:
8134  - Core/Events
8135  - Core/Options
8136  - Core/Element.Event
8137  - Core/Element.Dimensions
8138  - MooTools.More
8139
8140provides: [Scroller]
8141
8142...
8143*/
8144(function(){
8145
8146var Scroller = this.Scroller = new Class({
8147
8148	Implements: [Events, Options],
8149
8150	options: {
8151		area: 20,
8152		velocity: 1,
8153		onChange: function(x, y){
8154			this.element.scrollTo(x, y);
8155		},
8156		fps: 50
8157	},
8158
8159	initialize: function(element, options){
8160		this.setOptions(options);
8161		this.element = document.id(element);
8162		this.docBody = document.id(this.element.getDocument().body);
8163		this.listener = (typeOf(this.element) != 'element') ? this.docBody : this.element;
8164		this.timer = null;
8165		this.bound = {
8166			attach: this.attach.bind(this),
8167			detach: this.detach.bind(this),
8168			getCoords: this.getCoords.bind(this)
8169		};
8170	},
8171
8172	start: function(){
8173		this.listener.addEvents({
8174			mouseover: this.bound.attach,
8175			mouseleave: this.bound.detach
8176		});
8177		return this;
8178	},
8179
8180	stop: function(){
8181		this.listener.removeEvents({
8182			mouseover: this.bound.attach,
8183			mouseleave: this.bound.detach
8184		});
8185		this.detach();
8186		this.timer = clearInterval(this.timer);
8187		return this;
8188	},
8189
8190	attach: function(){
8191		this.listener.addEvent('mousemove', this.bound.getCoords);
8192	},
8193
8194	detach: function(){
8195		this.listener.removeEvent('mousemove', this.bound.getCoords);
8196		this.timer = clearInterval(this.timer);
8197	},
8198
8199	getCoords: function(event){
8200		this.page = (this.listener.get('tag') == 'body') ? event.client : event.page;
8201		if (!this.timer) this.timer = this.scroll.periodical(Math.round(1000 / this.options.fps), this);
8202	},
8203
8204	scroll: function(){
8205		var size = this.element.getSize(),
8206			scroll = this.element.getScroll(),
8207			pos = ((this.element != this.docBody) && (this.element != window)) ? this.element.getOffsets() : {x: 0, y: 0},
8208			scrollSize = this.element.getScrollSize(),
8209			change = {x: 0, y: 0},
8210			top = this.options.area.top || this.options.area,
8211			bottom = this.options.area.bottom || this.options.area;
8212		for (var z in this.page){
8213			if (this.page[z] < (top + pos[z]) && scroll[z] != 0){
8214				change[z] = (this.page[z] - top - pos[z]) * this.options.velocity;
8215			} else if (this.page[z] + bottom > (size[z] + pos[z]) && scroll[z] + size[z] != scrollSize[z]){
8216				change[z] = (this.page[z] - size[z] + bottom - pos[z]) * this.options.velocity;
8217			}
8218			change[z] = change[z].round();
8219		}
8220		if (change.y || change.x) this.fireEvent('change', [scroll.x + change.x, scroll.y + change.y]);
8221	}
8222
8223});
8224
8225})();
8226
8227
8228/*
8229---
8230
8231script: Tips.js
8232
8233name: Tips
8234
8235description: Class for creating nice tips that follow the mouse 
8235cursor when hovering an element.
8236
8237license: MIT-style license
8238
8239authors:
8240  - Valerio Proietti
8241  - Christoph Pojer
8242  - Luis Merino
8243
8244requires:
8245  - Core/Options
8246  - Core/Events
8247  - Core/Element.Event
8248  - Core/Element.Style
8249  - Core/Element.Dimensions
8250  - MooTools.More
8251
8252provides: [Tips]
8253
8254...
8255*/
8256
8257(function(){
8258
8259var read = function(option, element){
8260	return (option) ? (typeOf(option) == 'function' ? option(element) : element.get(option)) : '';
8261};
8262
8263var Tips = this.Tips = new Class({
8264
8265	Implements: [Events, Options],
8266
8267	options: {/*
8268		id: null,
8269		onAttach: function(element){},
8270		onDetach: function(element){},
8271		onBound: function(coords){},*/
8272		onShow: function(){
8273			this.tip.setStyle('display', 'block');
8274		},
8275		onHide: function(){
8276			this.tip.setStyle('display', 'none');
8277		},
8278		title: 'title',
8279		text: function(element){
8280			return element.get('rel') || element.get('href');
8281		},
8282		showDelay: 100,
8283		hideDelay: 100,
8284		className: 'tip-wrap',
8285		offset: {x: 16, y: 16},
8286		windowPadding: {x:0, y:0},
8287		fixed: false,
8288		waiAria: true,
8289		hideEmpty: false
8290	},
8291
8292	initialize: function(){
8293		var params = Array.link(arguments, {
8294			options: Type.isObject,
8295			elements: function(obj){
8296				return obj != null;
8297			}
8298		});
8299		this.setOptions(params.options);
8300		if (params.elements) this.attach(params.elements);
8301		this.container = new Element('div', {'class': 'tip'});
8302
8303		if (this.options.id){
8304			this.container.set('id', this.options.id);
8305			if (this.options.waiAria) this.attachWaiAria();
8306		}
8307	},
8308
8309	toElement: function(){
8310		if (this.tip) return this.tip;
8311
8312		this.tip = new Element('div', {
8313			'class': this.options.className,
8314			styles: {
8315				position: 'absolute',
8316				top: 0,
8317				left: 0,
8318				display: 'none'
8319			}
8320		}).adopt(
8321			new Element('div', {'class': 'tip-top'}),
8322			this.container,
8323			new Element('div', {'class': 'tip-bottom'})
8324		);
8325
8326		return this.tip;
8327	},
8328
8329	attachWaiAria: function(){
8330		var id = this.options.id;
8331		this.container.set('role', 'tooltip');
8332
8333		if (!this.waiAria){
8334			this.waiAria = {
8335				show: function(element){
8336					if (id) element.set('aria-describedby', id);
8337					this.container.set('aria-hidden', 'false');
8338				},
8339				hide: function(element){
8340					if (id) element.erase('aria-describedby');
8341					this.container.set('aria-hidden', 'true');
8342				}
8343			};
8344		}
8345		this.addEvents(this.waiAria);
8346	},
8347
8348	detachWaiAria: function(){
8349		if (this.waiAria){
8350			this.container.erase('role');
8351			this.container.erase('aria-hidden');
8352			this.removeEvents(this.waiAria);
8353		}
8354	},
8355
8356	attach: function(elements){
8357		$$(elements).each(function(element){
8358			var title = read(this.options.title, element),
8359				text = read(this.options.text, element);
8360
8361			element.set('title', '').store('tip:native', title).retrieve('tip:title', title);
8362			element.retrieve('tip:text', text);
8363			this.fireEvent('attach', [element]);
8364
8365			var events = ['enter', 'leave'];
8366			if (!this.options.fixed) events.push('move');
8367
8368			events.each(function(value){
8369				var event = element.retrieve('tip:' + value);
8370				if (!event) event = function(event){
8371					this['element' + value.capitalize()].apply(this, [event, element]);
8372				}.bind(this);
8373
8374				element.store('tip:' + value, event).addEvent('mouse' + value, event);
8375			}, this);
8376		}, this);
8377
8378		return this;
8379	},
8380
8381	detach: function(elements){
8382		$$(elements).each(function(element){
8383			['enter', 'leave', 'move'].each(function(value){
8384				element.removeEvent('mouse' + value, element.retrieve('tip:' + value)).eliminate('tip:' + value);
8385			});
8386
8387			this.fireEvent('detach', [element]);
8388
8389			if (this.options.title == 'title'){ // This is necessary to check if we can revert the title
8390				var original = element.retrieve('tip:native');
8391				if (original) element.set('title', original);
8392			}
8393		}, this);
8394
8395		return this;
8396	},
8397
8398	elementEnter: function(event, element){
8399		clearTimeout(this.timer);
8400		this.timer = (function(){
8401			this.container.empty();
8402			var showTip = !this.options.hideEmpty;
8403			['title', 'text'].each(function(value){
8404				var content = element.retrieve('tip:' + value);
8405				var div = this['_' + value + 'Element'] = new Element('div', {
8406					'class': 'tip-' + value
8407				}).inject(this.container);
8408				if (content){
8409					this.fill(div, content);
8410					showTip = true;
8411				}
8412			}, this);
8413			if (showTip){
8414				this.show(element);
8415			} else {
8416				this.hide(element);
8417			}
8418			this.position((this.options.fixed) ? {page: element.getPosition()} : event);
8419		}).delay(this.options.showDelay, this);
8420	},
8421
8422	elementLeave: function(event, element){
8423		clearTimeout(this.timer);
8424		this.timer = this.hide.delay(this.options.hideDelay, this, element);
8425		this.fireForParent(event, element);
8426	},
8427
8428	setTitle: function(title){
8429		if (this._titleElement){
8430			this._titleElement.empty();
8431			this.fill(this._titleElement, title);
8432		}
8433		return this;
8434	},
8435
8436	setText: function(text){
8437		if (this._textElement){
8438			this._textElement.empty();
8439			this.fill(this._textElement, text);
8440		}
8441		return this;
8442	},
8443
8444	fireForParent: function(event, element){
8445		element = element.getParent();
8446		if (!element || element == document.body) return;
8447		if (element.retrieve('tip:enter')) element.fireEvent('mouseenter', event);
8448		else this.fireForParent(event, element);
8449	},
8450
8451	elementMove: function(event, element){
8452		this.position(event);
8453	},
8454
8455	position: function(event){
8456		if (!this.tip) document.id(this);
8457
8458		var size = window.getSize(), scroll = window.getScroll(),
8459			tip = {x: this.tip.offsetWidth, y: this.tip.offsetHeight},
8460			props = {x: 'left', y: 'top'},
8461			bounds = {y: false, x2: false, y2: false, x: false},
8462			obj = {};
8463
8464		for (var z in props){
8465			obj[props[z]] = event.page[z] + this.options.offset[z];
8466			if (obj[props[z]] < 0) bounds[z] = true;
8467			if ((obj[props[z]] + tip[z] - scroll[z]) > size[z] - this.options.windowPadding[z]){
8468				obj[props[z]] = event.page[z] - this.options.offset[z] - tip[z];
8469				bounds[z+'2'] = true;
8470			}
8471		}
8472
8473		this.fireEvent('bound', bounds);
8474		this.tip.setStyles(obj);
8475	},
8476
8477	fill: function(element, contents){
8478		if (typeof contents == 'string') element.set('html', contents);
8479		else element.adopt(contents);
8480	},
8481
8482	show: function(element){
8483		if (!this.tip) document.id(this);
8484		if (!this.tip.getParent()) this.tip.inject(document.body);
8485		this.fireEvent('show', [this.tip, element]);
8486	},
8487
8488	hide: function(element){
8489		if (!this.tip) document.id(this);
8490		this.fireEvent('hide', [this.tip, element]);
8491	}
8492
8493});
8494
8495})();
8496
8497/*
8498---
8499name: Locale.CH.Number
8500description: Number messages for Switzerland.
8501license: MIT-style license
8502authors:
8503  - Kim D. Jeker
8504requires:
8505  - Locale
8506provides: [Locale.CH.Number]
8507...
8508*/
8509
8510Locale.define('CH', 'Number', {
8511
8512	decimal: ',',
8513	group: '\'',
8514
8515	currency: {
8516		decimal: '.',
8517		suffix: ' CHF'
8518	}
8519
8520});
8521
8522/*
8523---
8524
8525name: Locale.EU.Number
8526
8527description: Number messages for Europe.
8528
8529license: MIT-style license
8530
8531authors:
8532  - Arian Stolwijk
8533
8534requires:
8535  - Locale
8536
8537provides: [Locale.EU.Number]
8538
8539...
8540*/
8541
8542Locale.define('EU', 'Number', {
8543
8544	decimal: ',',
8545	group: '.',
8546
8547	currency: {
8548		prefix: '€ '
8549	}
8550
8551});
8552
8553/*
8554---
8555
8556script: Locale.Set.From.js
8557
8558name: Locale.Set.From
8559
8560description: Provides an alternative way to create Locale.Set objects.
8561
8562license: MIT-style license
8563
8564authors:
8565  - Tim Wienk
8566
8567requires:
8568  - Core/JSON
8569  - Locale
8570
8571provides: Locale.Set.From
8572
8573...
8574*/
8575
8576(function(){
8577
8578var parsers = {
8579	'json': JSON.decode
8580};
8581
8582Locale.Set.defineParser = function(name, fn){
8583	parsers[name] = fn;
8584};
8585
8586Locale.Set.from = function(set, type){
8587	if (instanceOf(set, Locale.Set)) return set;
8588
8589	if (!type && typeOf(set) == 'string') type = 'json';
8590	if (parsers[type]) set = parsers[type](set);
8591
8592	var locale = new Locale.Set;
8593
8594	locale.sets = set.sets || {};
8595
8596	if (set.inherits){
8597		locale.inherits.locales = Array.convert(set.inherits.locales);
8598		locale.inherits.sets = set.inherits.sets || {};
8599	}
8600
8601	return locale;
8602};
8603
8604})();
8605
8606/*
8607---
8608
8609name: Locale.ZA.Number
8610
8611description: Number messages for ZA.
8612
8613license: MIT-style license
8614
8615authors:
8616  - Werner Mollentze
8617
8618requires:
8619  - Locale
8620
8621provides: [Locale.ZA.Number]
8622
8623...
8624*/
8625
8626Locale.define('ZA', 'Number', {
8627
8628	decimal: '.',
8629	group: ',',
8630
8631	currency: {
8632		prefix: 'R '
8633	}
8634
8635});
8636
8637
8638
8639/*
8640---
8641
8642name: Locale.af-ZA.Date
8643
8644description: Date messages for ZA Afrikaans.
8645
8646license: MIT-style license
8647
8648authors:
8649  - Werner Mollentze
8650
8651requires:
8652  - Locale
8653
8654provides: [Locale.af-ZA.Date]
8655
8656...
8657*/
8658
8659Locale.define('af-ZA', 'Date', {
8660
8661	months: ['Januarie', 'Februarie', 'Maart', 'April', 'Mei', 'Junie', 'Julie', 'Augustus', 'September', 'Oktober', 'November', 'Desember'],
8662	months_abbr: ['Jan', 'Feb', 'Mrt', 'Apr', 'Mei', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Des'],
8663	days: ['Sondag', 'Maandag', 'Dinsdag', 'Woensdag', 'Donderdag', 'Vrydag', 'Saterdag'],
8664	days_abbr: ['Son', 'Maa', 'Din', 'Woe', 'Don', 'Vry', 'Sat'],
8665
8666	// Culture's date order: MM/DD/YYYY
8667	dateOrder: ['date', 'month', 'year'],
8668	shortDate: '%d-%m-%Y',
8669	shortTime: '%H:%M',
8670	AM: 'VM',
8671	PM: 'NM',
8672	firstDayOfWeek: 1,
8673
8674	// Date.Extras
8675	ordinal: function(dayOfMonth){
8676		return ((dayOfMonth > 1 && dayOfMonth < 20 && dayOfMonth != 8) || (dayOfMonth > 100 && dayOfMonth.toString().substr(-2, 1) == '1')) ? 'de' : 'ste';
8677	},
8678
8679	lessThanMinuteAgo: 'minder as \'n minuut gelede',
8680	minuteAgo: 'ongeveer \'n minuut gelede',
8681	minutesAgo: '{delta} minute gelede',
8682	hourAgo: 'omtret \'n uur gelede',
8683	hoursAgo: 'ongeveer {delta} ure gelede',
8684	dayAgo: '1 dag gelede',
8685	daysAgo: '{delta} dae gelede',
8686	weekAgo: '1 week gelede',
8687	weeksAgo: '{delta} weke gelede',
8688	monthAgo: '1 maand gelede',
8689	monthsAgo: '{delta} maande gelede',
8690	yearAgo: '1 jaar gelede',
8691	yearsAgo: '{delta} jare gelede',
8692
8693	lessThanMinuteUntil: 'oor minder as \'n minuut',
8694	minuteUntil: 'oor ongeveer \'n minuut',
8695	minutesUntil: 'oor {delta} minute',
8696	hourUntil: 'oor ongeveer \'n uur',
8697	hoursUntil: 'oor {delta} uur',
8698	dayUntil: 'oor ongeveer \'n dag',
8699	daysUntil: 'oor {delta} dae',
8700	weekUntil: 'oor \'n week',
8701	weeksUntil: 'oor {delta} weke',
8702	monthUntil: 'oor \'n maand',
8703	monthsUntil: 'oor {delta} maande',
8704	yearUntil: 'oor \'n jaar',
8705	yearsUntil: 'oor {delta} jaar'
8706
8707});
8708
8709/*
8710---
8711
8712name: Locale.af-ZA.Form.Validator
8713
8714description: Form Validator messages for Afrikaans.
8715
8716license: MIT-style license
8717
8718authors:
8719  - Werner Mollentze
8720
8721requires:
8722  - Locale
8723
8724provides: [Locale.af-ZA.Form.Validator]
8725
8726...
8727*/
8728
8729Locale.define('af-ZA', 'FormValidator', {
8730
8731	required: 'Hierdie veld word vereis.',
8732	length: 'Voer asseblief {length} karakters in (u het {elLength} karakters ingevoer)',
8733	minLength: 'Voer asseblief ten minste {minLength} karakters in (u het {length} karakters ingevoer).',
8734	maxLength: 'Moet asseblief nie meer as {maxLength} karakters invoer nie (u het {length} karakters ingevoer).',
8735	integer: 'Voer asseblief \'n heelgetal in hierdie veld in. Getalle met desimale (bv. 1.25) word nie toegelaat nie.',
8736	numeric: 'Voer asseblief slegs numeriese waardes in hierdie veld in (bv. "1" of "1.1" of "-1" of "-1.1").',
8737	digits: 'Gebruik asseblief slegs nommers en punktuasie in hierdie veld. (by voorbeeld, \'n telefoon nommer wat koppeltekens en punte bevat is toelaatbaar).',
8738	alpha: 'Gebruik asseblief slegs letters (a-z) binne-in hierdie veld. Geen spasies of ander karakters word toegelaat nie.',
8739	alphanum: 'Gebruik asseblief slegs letters (a-z) en nommers (0-9) binne-in hierdie veld. Geen spasies of ander karakters word toegelaat nie.',
8740	dateSuchAs: 'Voer asseblief \'n geldige datum soos {date} in',
8741	dateInFormatMDY: 'Voer asseblief \'n geldige datum soos MM/DD/YYYY in (bv. "12/31/1999")',
8742	email: 'Voer asseblief \'n geldige e-pos adres in. Byvoorbeeld "[email protected]".',
8743	url: 'Voer asseblief \'n geldige bronadres (URL) soos http://www.example.com in.',
8744	currencyDollar: 'Voer asseblief \'n geldige $ bedrag in. Byvoorbeeld $100.00 .',
8745	oneRequired: 'Voer asseblief iets in vir ten minste een van hierdie velde.',
8746	errorPrefix: 'Fout: ',
8747	warningPrefix: 'Waarskuwing: ',
8748
8749	// Form.Validator.Extras
8750	noSpace: 'Daar mag geen spasies in hierdie toevoer wees nie.',
8751	reqChkByNode: 'Geen items is gekies nie.',
8752	requiredChk: 'Hierdie veld word vereis.',
8753	reqChkByName: 'Kies asseblief \'n {label}.',
8754	match: 'Hierdie veld moet by die {matchName} veld pas',
8755	startDate: 'die begin datum',
8756	endDate: 'die eind datum',
8757	currentDate: 'die huidige datum',
8758	afterDate: 'Die datum moet dieselfde of na {label} wees.',
8759	beforeDate: 'Die datum moet dieselfde of voor {label} wees.',
8760	startMonth: 'Kies asseblief \'n begin maand',
8761	sameMonth: 'Hierdie twee datums moet in dieselfde maand wees - u moet een of beide verander.',
8762	creditcard: 'Die ingevoerde kredietkaart nommer is ongeldig. Bevestig asseblief die nommer en probeer weer. {length} syfers is ingevoer.'
8763
8764});
8765
8766/*
8767---
8768
8769name: Locale.af-ZA.Number
8770
8771description: Number messages for ZA Afrikaans.
8772
8773license: MIT-style license
8774
8775authors:
8776  - Werner Mollentze
8777
8778requires:
8779  - Locale
8780  - Locale.ZA.Number
8781
8782provides: [Locale.af-ZA.Number]
8783
8784...
8785*/
8786
8787Locale.define('af-ZA').inherit('ZA', 'Number');
8788
8789/*
8790---
8791
8792name: Locale.ar.Date
8793
8794description: Date messages for Arabic.
8795
8796license: MIT-style license
8797
8798authors:
8799  - Chafik Barbar
8800
8801requires:
8802  - Locale
8803
8804provides: [Locale.ar.Date]
8805
8806...
8807*/
8808
8809Locale.define('ar', 'Date', {
8810
8811	// Culture's date order: DD/MM/YYYY
8812	dateOrder: ['date', 'month', 'year'],
8813	shortDate: '%d/%m/%Y',
8814	shortTime: '%H:%M'
8815
8816});
8817
8818/*
8819---
8820
8821name: Locale.ar.Form.Validator
8822
8823description: Form Validator messages for Arabic.
8824
8825license: MIT-style license
8826
8827authors:
8828  - Chafik Barbar
8829
8830requires:
8831  - Locale
8832
8833provides: [Locale.ar.Form.Validator]
8834
8835...
8836*/
8837
8838Locale.define('ar', 'FormValidator', {
8839
8840	required: 'هذا الحقل مطلوب.',
8841	minLength: 'رجاءً إدخال {minLength} أحرف على الأقل (تم إدخال {length} أحرف).',
8842	maxLength: 'الرجاء عدم إدخال أكثر من {maxLength} أحرف (تم إدخال {length} أحرف).',
8843	integer: 'الرجاء إدخال عدد صحيح في هذا الحقل. أي رقم ذو كسر عشري أو مئوي (مثال 1.25 ) غير مسموح.',
8844	numeric: 'الرجاء إدخال قيم رقمية في هذا الحقل (مثال "1" أو "1.1" أو "-1" أو "-1.1").',
8845	digits: 'الرجاء أستخدام قيم رقمية وعلامات ترقيمية فقط في هذا الحقل (مثال, رقم هاتف مع نقطة أو شحطة)',
8846	alpha: 'الرجاء أستخدام أحرف فقط (ا-ي) في هذا الحقل. أي فراغات أو علامات غير مسموحة.',
8847	alphanum: 'الرجاء أستخدام أحرف فقط (ا-ي) أو أرقام (0-9) فقط في هذا الحقل. أي فراغات أو علامات غير مسموحة.',
8848	dateSuchAs: 'الرجاء إدخال تاريخ صحيح كالتالي {date}',
8849	dateInFormatMDY: 'الرجاء إدخال تاريخ صحيح (مثال, 31-12-1999)',
8850	email: 'الرجاء إدخال بريد إلكتروني صحيح.',
8851	url: 'الرجاء إدخال عنوان إلكتروني صحيح مثل http://www.example.com',
8852	currencyDollar: 'الرجاء إدخال قيمة $ صحيحة. مثال, 100.00$',
8853	oneRequired: 'الرجاء إدخال قيمة في أحد هذه الحقول على الأقل.',
8854	errorPrefix: 'خطأ: ',
8855	warningPrefix: 'تحذير: '
8856
8857});
8858
8859/*
8860---
8861
8862name: Locale.ca-CA.Date
8863
8864description: Date messages for Catalan.
8865
8866license: MIT-style license
8867
8868authors:
8869  - Ãlfons Sanchez
8870
8871requires:
8872  - Locale
8873
8874provides: [Locale.ca-CA.Date]
8875
8876...
8877*/
8878
8879Locale.define('ca-CA', 'Date', {
8880
8881	months: ['Gener', 'Febrer', 'Març', 'Abril', 'Maig', 'Juny', 'Juli', 'Agost', 'Setembre', 'Octubre', 'Novembre', 'Desembre'],
8882	months_abbr: ['gen.', 'febr.', 'març', 'abr.', 'maig', 'juny', 'jul.', 'ag.', 'set.', 'oct.', 'nov.', 'des.'],
8883	days: ['Diumenge', 'Dilluns', 'Dimarts', 'Dimecres', 'Dijous', 'Divendres', 'Dissabte'],
8884	days_abbr: ['dg', 'dl', 'dt', 'dc', 'dj', 'dv', 'ds'],
8885
8886	// Culture's date order: DD/MM/YYYY
8887	dateOrder: ['date', 'month', 'year'],
8888	shortDate: '%d/%m/%Y',
8889	shortTime: '%H:%M',
8890	AM: 'AM',
8891	PM: 'PM',
8892	firstDayOfWeek: 0,
8893
8894	// Date.Extras
8895	ordinal: '',
8896
8897	lessThanMinuteAgo: 'fa menys d`un minut',
8898	minuteAgo: 'fa un minut',
8899	minutesAgo: 'fa {delta} minuts',
8900	hourAgo: 'fa un hora',
8901	hoursAgo: 'fa unes {delta} hores',
8902	dayAgo: 'fa un dia',
8903	daysAgo: 'fa {delta} dies',
8904
8905	lessThanMinuteUntil: 'menys d`un minut des d`ara',
8906	minuteUntil: 'un minut des d`ara',
8907	minutesUntil: '{delta} minuts des d`ara',
8908	hourUntil: 'un hora des d`ara',
8909	hoursUntil: 'unes {delta} hores des d`ara',
8910	dayUntil: '1 dia des d`ara',
8911	daysUntil: '{delta} dies des d`ara'
8912
8913});
8914
8915/*
8916---
8917
8918name: Locale.ca-CA.Form.Validator
8919
8920description: Form Validator messages for Catalan.
8921
8922license: MIT-style license
8923
8924authors:
8925  - Miquel Hudin
8926  - Ãlfons Sanchez
8927
8928requires:
8929  - Locale
8930
8931provides: [Locale.ca-CA.Form.Validator]
8932
8933...
8934*/
8935
8936Locale.define('ca-CA', 'FormValidator', {
8937
8938	required: 'Aquest camp es obligatori.',
8939	minLength: 'Per favor introdueix al menys {minLength} caracters (has introduit {length} caracters).',
8940	maxLength: 'Per favor introdueix no mes de {maxLength} caracters (has introduit {length} caracters).',
8941	integer: 'Per favor introdueix un nombre enter en aquest camp. Nombres amb decimals (p.e. 1,25) no estan permesos.',
8942	numeric: 'Per favor introdueix sols valors numerics en aquest camp (p.e. "1" o "1,1" o "-1" o "-1,1").',
8943	digits: 'Per favor usa sols numeros i puntuacio en aquest camp (per exemple, un nombre de telefon amb guions i punts no esta permes).',
8944	alpha: 'Per favor utilitza lletres nomes (a-z) en aquest camp. No s´admiteixen espais ni altres caracters.',
8945	alphanum: 'Per favor, utilitza nomes lletres (a-z) o numeros (0-9) en aquest camp. No s´admitei
8945xen espais ni altres caracters.',
8946	dateSuchAs: 'Per favor introdueix una data valida com {date}',
8947	dateInFormatMDY: 'Per favor introdueix una data valida com DD/MM/YYYY (p.e. "31/12/1999")',
8948	email: 'Per favor, introdueix una adreça de correu electronic valida. Per exemple, "[email protected]".',
8949	url: 'Per favor introdueix una URL valida com http://www.example.com.',
8950	currencyDollar: 'Per favor introdueix una quantitat valida de €. Per exemple €100,00 .',
8951	oneRequired: 'Per favor introdueix alguna cosa per al menys una d´aquestes entrades.',
8952	errorPrefix: 'Error: ',
8953	warningPrefix: 'Avis: ',
8954
8955	// Form.Validator.Extras
8956	noSpace: 'No poden haver espais en aquesta entrada.',
8957	reqChkByNode: 'No hi han elements seleccionats.',
8958	requiredChk: 'Aquest camp es obligatori.',
8959	reqChkByName: 'Per favor selecciona una {label}.',
8960	match: 'Aquest camp necessita coincidir amb el camp {matchName}',
8961	startDate: 'la data de inici',
8962	endDate: 'la data de fi',
8963	currentDate: 'la data actual',
8964	afterDate: 'La data deu ser igual o posterior a {label}.',
8965	beforeDate: 'La data deu ser igual o anterior a {label}.',
8966	startMonth: 'Per favor selecciona un mes d´orige',
8967	sameMonth: 'Aquestes dos dates deuen estar dins del mateix mes - deus canviar una o altra.'
8968
8969});
8970
8971/*
8972---
8973
8974name: Locale.cs-CZ.Date
8975
8976description: Date messages for Czech.
8977
8978license: MIT-style license
8979
8980authors:
8981  - Jan Černý chemiX
8982  - Christopher Zukowski
8983
8984requires:
8985  - Locale
8986
8987provides: [Locale.cs-CZ.Date]
8988
8989...
8990*/
8991(function(){
8992
8993// Czech language pluralization rules, see http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
8994// one -> n is 1;            1
8995// few -> n in 2..4;         2-4
8996// other -> everything else  0, 5-999, 1.31, 2.31, 5.31...
8997var pluralize = function(n, one, few, other){
8998	if (n == 1) return one;
8999	else if (n == 2 || n == 3 || n == 4) return few;
9000	else return other;
9001};
9002
9003Locale.define('cs-CZ', 'Date', {
9004
9005	months: ['Leden', 'Únor', 'Březen', 'Duben', 'Květen', 'Červen', 'Červenec', 'Srpen', 'Září', 'Říjen', 'Listopad', 'Prosinec'],
9006	months_abbr: ['ledna', 'února', 'března', 'dubna', 'května', 'června', 'července', 'srpna', 'září', 'října', 'listopadu', 'prosince'],
9007	days: ['Neděle', 'Pondělí', 'Úterý', 'Středa', 'Čtvrtek', 'Pátek', 'Sobota'],
9008	days_abbr: ['ne', 'po', 'út', 'st', 'čt', 'pá', 'so'],
9009
9010	// Culture's date order: DD.MM.YYYY
9011	dateOrder: ['date', 'month', 'year'],
9012	shortDate: '%d.%m.%Y',
9013	shortTime: '%H:%M',
9014	AM: 'dop.',
9015	PM: 'odp.',
9016	firstDayOfWeek: 1,
9017
9018	// Date.Extras
9019	ordinal: '.',
9020
9021	lessThanMinuteAgo: 'před chvílí',
9022	minuteAgo: 'přibližně před minutou',
9023	minutesAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'minutou', 'minutami', 'minutami'); },
9024	hourAgo: 'přibližně před hodinou',
9025	hoursAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'hodinou', 'hodinami', 'hodinami'); },
9026	dayAgo: 'před dnem',
9027	daysAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'dnem', 'dny', 'dny'); },
9028	weekAgo: 'před týdnem',
9029	weeksAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'týdnem', 'týdny', 'týdny'); },
9030	monthAgo: 'před měsícem',
9031	monthsAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'měsícem', 'měsíci', 'měsíci'); },
9032	yearAgo: 'před rokem',
9033	yearsAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'rokem', 'lety', 'lety'); },
9034
9035	lessThanMinuteUntil: 'za chvíli',
9036	minuteUntil: 'přibližně za minutu',
9037	minutesUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'minutu', 'minuty', 'minut'); },
9038	hourUntil: 'přibližně za hodinu',
9039	hoursUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'hodinu', 'hodiny', 'hodin'); },
9040	dayUntil: 'za den',
9041	daysUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'den', 'dny', 'dnů'); },
9042	weekUntil: 'za týden',
9043	weeksUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'týden', 'týdny', 'týdnů'); },
9044	monthUntil: 'za měsíc',
9045	monthsUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'měsíc', 'měsíce', 'měsíců'); },
9046	yearUntil: 'za rok',
9047	yearsUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'rok', 'roky', 'let'); }
9048});
9049
9050})();
9051
9052/*
9053---
9054
9055name: Locale.cs-CZ.Form.Validator
9056
9057description: Form Validator messages for Czech.
9058
9059license: MIT-style license
9060
9061authors:
9062  - Jan Černý chemiX
9063
9064requires:
9065  - Locale
9066
9067provides: [Locale.cs-CZ.Form.Validator]
9068
9069...
9070*/
9071
9072Locale.define('cs-CZ', 'FormValidator', {
9073
9074	required: 'Tato položka je povinná.',
9075	minLength: 'Zadejte prosím alespoň {minLength} znaků (napsáno {length} znaků).',
9076	maxLength: 'Zadejte prosím méně než {maxLength} znaků (nápsáno {length} znaků).',
9077	integer: 'Zadejte prosím celé číslo. Desetinná čísla (např. 1.25) nejsou povolena.',
9078	numeric: 'Zadejte jen číselné hodnoty (tj. "1" nebo "1.1" nebo "-1" nebo "-1.1").',
9079	digits: 'Zadejte prosím pouze čísla a interpunkční znaménka(například telefonní číslo s pomlčkami nebo tečkami je povoleno).',
9080	alpha: 'Zadejte prosím pouze písmena (a-z). Mezery nebo jiné znaky nejsou povoleny.',
9081	alphanum: 'Zadejte prosím pouze písmena (a-z) nebo číslice (0-9). Mezery nebo jiné znaky nejsou povoleny.',
9082	dateSuchAs: 'Zadejte prosím platné datum jako {date}',
9083	dateInFormatMDY: 'Zadejte prosím platné datum jako MM / DD / RRRR (tj. "12/31/1999")',
9084	email: 'Zadejte prosím platnou e-mailovou adresu. Například "[email protected]".',
9085	url: 'Zadejte prosím platnou URL adresu jako http://www.example.com.',
9086	currencyDollar: 'Zadejte prosím platnou částku. Například $100.00.',
9087	oneRequired: 'Zadejte prosím alespoň jednu hodnotu pro tyto položky.',
9088	errorPrefix: 'Chyba: ',
9089	warningPrefix: 'Upozornění: ',
9090
9091	// Form.Validator.Extras
9092	noSpace: 'V této položce nejsou povoleny mezery',
9093	reqChkByNode: 'Nejsou vybrány žádné položky.',
9094	requiredChk: 'Tato položka je vyžadována.',
9095	reqChkByName: 'Prosím vyberte {label}.',
9096	match: 'Tato položka se musí shodovat s položkou {matchName}',
9097	startDate: 'datum zahájení',
9098	endDate: 'datum ukončení',
9099	currentDate: 'aktuální datum',
9100	afterDate: 'Datum by mělo být stejné nebo větší než {label}.',
9101	beforeDate: 'Datum by mělo být stejné nebo menší než {label}.',
9102	startMonth: 'Vyberte počáteční měsíc.',
9103	sameMonth: 'Tyto dva datumy musí být ve stejném měsíci - změňte jeden z nich.',
9104	creditcard: 'Zadané číslo kreditní karty je neplatné. Prosím opravte ho. Bylo zadáno {length} čísel.'
9105
9106});
9107
9108/*
9109---
9110
9111name: Locale.da-DK.Date
9112
9113description: Date messages for Danish.
9114
9115license: MIT-style license
9116
9117authors:
9118  - Martin Overgaard
9119  - Henrik Hansen
9120
9121requires:
9122  - Locale
9123
9124provides: [Locale.da-DK.Date]
9125
9126...
9127*/
9128
9129Locale.define('da-DK', 'Date', {
9130
9131	months: ['Januar', 'Februar', 'Marts', 'April', 'Maj', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'December'],
9132	months_abbr: ['jan.', 'feb.', 'mar.', 'apr.', 'maj.', 'jun.', 'jul.', 'aug.', 'sep.', 'okt.', 'nov.', 'dec.'],
9133	days: ['Søndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lørdag'],
9134	days_abbr: ['søn', 'man', 'tir', 'ons', 'tor', 'fre', 'lør'],
9135
9136	// Culture's date order: DD-MM-YYYY
9137	dateOrder: ['date', 'month', 'year'],
9138	shortDate: '%d-%m-%Y',
9139	shortTime: '%H:%M',
9140	AM: 'AM',
9141	PM: 'PM',
9142	firstDayOfWeek: 1,
9143
9144	// Date.Extras
9145	ordinal: '.',
9146
9147	lessThanMinuteAgo: 'mindre end et minut siden',
9148	minuteAgo: 'omkring et minut siden',
9149	minutesAgo: '{delta} minutter siden',
9150	hourAgo: 'omkring en time siden',
9151	hoursAgo: 'omkring {delta} timer siden',
9152	dayAgo: '1 dag siden',
9153	daysAgo: '{delta} dage siden',
9154	weekAgo: '1 uge siden',
9155	weeksAgo: '{delta} uger siden',
9156	monthAgo: '1 måned siden',
9157	monthsAgo: '{delta} måneder siden',
9158	yearAgo: '1 år siden',
9159	yearsAgo: '{delta} år siden',
9160
9161	lessThanMinuteUntil: 'mindre end et minut fra nu',
9162	minuteUntil: 'omkring et minut fra nu',
9163	minutesUntil: '{delta} minutter fra nu',
9164	hourUntil: 'omkring en time fra nu',
9165	hoursUntil: 'omkring {delta} timer fra nu',
9166	dayUntil: '1 dag fra nu',
9167	daysUntil: '{delta} dage fra nu',
9168	weekUntil: '1 uge fra nu',
9169	weeksUntil: '{delta} uger fra nu',
9170	monthUntil: '1 måned fra nu',
9171	monthsUntil: '{delta} måneder fra nu',
9172	yearUntil: '1 år fra nu',
9173	yearsUntil: '{delta} år fra nu'
9174
9175});
9176
9177/*
9178---
9179
9180name: Locale.da-DK.Form.Validator
9181
9182description: Form Validator messages for Danish.
9183
9184license: MIT-style license
9185
9186authors:
9187  - Martin Overgaard
9188
9189requires:
9190  - Locale
9191
9192provides: [Locale.da-DK.Form.Validator]
9193
9194...
9195*/
9196
9197Locale.define('da-DK', 'FormValidator', {
9198
9199	required: 'Feltet skal udfyldes.',
9200	minLength: 'Skriv mindst {minLength} tegn (du skrev {length} tegn).',
9201	maxLength: 'Skriv maksimalt {maxLength} tegn (du skrev {length} tegn).',
9202	integer: 'Skriv et tal i dette felt. Decimal tal (f.eks. 1.25) er ikke tilladt.',
9203	numeric: 'Skriv kun tal i dette felt (i.e. "1" eller "1.1" eller "-1" eller "-1.1").',
9204	digits: 'Skriv kun tal og tegnsætning i dette felt (eksempel, et telefon nummer med bindestreg eller punktum er tilladt).',
9205	alpha: 'Skriv kun bogstaver (a-z) i dette felt. Mellemrum og andre tegn er ikke tilladt.',
9206	alphanum: 'Skriv kun bogstaver (a-z) eller tal (0-9) i dette felt. Mellemrum og andre tegn er ikke tilladt.',
9207	dateSuchAs: 'Skriv en gyldig dato som {date}',
9208	dateInFormatMDY: 'Skriv dato i formatet DD-MM-YYYY (f.eks. "31-12-1999")',
9209	email: 'Skriv en gyldig e-mail adresse. F.eks "[email protected]".',
9210	url: 'Skriv en gyldig URL adresse. F.eks "http://www.example.com".',
9211	currencyDollar: 'Skriv et gldigt beløb. F.eks Kr.100.00 .',
9212	oneRequired: 'Et eller flere af felterne i denne formular skal udfyldes.',
9213	errorPrefix: 'Fejl: ',
9214	warningPrefix: 'Advarsel: ',
9215
9216	// Form.Validator.Extras
9217	noSpace: 'Der må ikke benyttes mellemrum i dette felt.',
9218	reqChkByNode: 'Foretag et valg.',
9219	requiredChk: 'Dette felt skal udfyldes.',
9220	reqChkByName: 'Vælg en {label}.',
9221	match: 'Dette felt skal matche {matchName} feltet',
9222	startDate: 'start dato',
9223	endDate: 'slut dato',
9224	currentDate: 'dags dato',
9225	afterDate: 'Datoen skal være større end eller lig med {label}.',
9226	beforeDate: 'Datoen skal være mindre end eller lig med {label}.',
9227	startMonth: 'Vælg en start måned',
9228	sameMonth: 'De valgte datoer skal være i samme måned - skift en af dem.'
9229
9230});
9231
9232/*
9233---
9234
9235name: Locale.de-DE.Date
9236
9237description: Date messages for German.
9238
9239license: MIT-style license
9240
9241authors:
9242  - Christoph Pojer
9243  - Frank Rossi
9244  - Ulrich Petri
9245  - Fabian Beiner
9246
9247requires:
9248  - Locale
9249
9250provides: [Locale.de-DE.Date]
9251
9252...
9253*/
9254
9255Locale.define('de-DE', 'Date', {
9256
9257	months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
9258	months_abbr: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'],
9259	days: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
9260	days_abbr: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
9261
9262	// Culture's date order: DD.MM.YYYY
9263	dateOrder: ['date', 'month', 'year'],
9264	shortDate: '%d.%m.%Y',
9265	shortTime: '%H:%M',
9266	AM: 'vormittags',
9267	PM: 'nachmittags',
9268	firstDayOfWeek: 1,
9269
9270	// Date.Extras
9271	ordinal: '.',
9272
9273	lessThanMinuteAgo: 'vor weniger als einer Minute',
9274	minuteAgo: 'vor einer Minute',
9275	minutesAgo: 'vor {delta} Minuten',
9276	hourAgo: 'vor einer Stunde',
9277	hoursAgo: 'vor {delta} Stunden',
9278	dayAgo: 'vor einem Tag',
9279	daysAgo: 'vor {delta} Tagen',
9280	weekAgo: 'vor einer Woche',
9281	weeksAgo: 'vor {delta} Wochen',
9282	monthAgo: 'vor einem Monat',
9283	monthsAgo: 'vor {delta} Monaten',
9284	yearAgo: 'vor einem Jahr',
9285	yearsAgo: 'vor {delta} Jahren',
9286
9287	lessThanMinuteUntil: 'in weniger als einer Minute',
9288	minuteUntil: 'in einer Minute',
9289	minutesUntil: 'in {delta} Minuten',
9290	hourUntil: 'in ca. einer Stunde',
9291	hoursUntil: 'in ca. {delta} Stunden',
9292	dayUntil: 'in einem Tag',
9293	daysUntil: 'in {delta} Tagen',
9294	weekUntil: 'in einer Woche',
9295	weeksUntil: 'in {delta} Wochen',
9296	monthUntil: 'in einem Monat',
9297	monthsUntil: 'in {delta} Monaten',
9298	yearUntil: 'in einem Jahr',
9299	yearsUntil: 'in {delta} Jahren'
9300
9301});
9302
9303/*
9304---
9305
9306name: Locale.de-CH.Date
9307
9308description: Date messages for German (Switzerland).
9309
9310license: MIT-style license
9311
9312authors:
9313  - Michael van der Weg
9314
9315requires:
9316  - Locale
9317  - Locale.de-DE.Date
9318
9319provides: [Locale.de-CH.Date]
9320
9321...
9322*/
9323
9324Locale.define('de-CH').inherit('de-DE', 'Date');
9325
9326/*
9327---
9328
9329name: Locale.de-CH.Form.Validator
9330
9331description: Form Validator messages for German (Switzerland).
9332
9333license: MIT-style license
9334
9335authors:
9336  - Michael van der Weg
9337
9338requires:
9339  - Locale
9340
9341provides: [Locale.de-CH.Form.Validator]
9342
9343...
9344*/
9345
9346Locale.define('de-CH', 'FormValidator', {
9347
9348	required: 'Dieses Feld ist obligatorisch.',
9349	minLength: 'Geben Sie bitte mindestens {minLength} Zeichen ein (Sie haben {length} Zeichen eingegeben).',
9350	maxLength: 'Bitte geben Sie nicht mehr als {maxLength} Zeichen ein (Sie haben {length} Zeichen eingegeben).',
9351	integer: 'Geben Sie bitte eine ganze Zahl ein. Dezimalzahlen (z.B. 1.25) sind nicht erlaubt.',
9352	numeric: 'Geben Sie bitte nur Zahlenwerte in dieses Eingabefeld ein (z.B. &quot;1&quot;, &quot;1.1&quot;, &quot;-1&quot; oder &quot;-1.1&quot;).',
9353	digits: 'Benutzen Sie bitte nur Zahlen und Satzzeichen in diesem Eingabefeld (erlaubt ist z.B. eine Telefonnummer mit Bindestrichen und Punkten).',
9354	alpha: 'Benutzen Sie bitte nur Buchstaben (a-z) in diesem Feld. Leerzeichen und andere Zeichen sind nicht erlaubt.',
9355	alphanum: 'Benutzen Sie bitte nur Buchstaben (a-z) und Zahlen (0-9) in diesem Eingabefeld. Leerzeichen und andere Zeichen sind nicht erlaubt.',
9356	dateSuchAs: 'Geben Sie bitte ein g&uuml;ltiges Datum ein. Wie zum Beispiel {date}',
9357	dateInFormatMDY: 'Geben Sie bitte ein g&uuml;ltiges Datum ein. Wie zum Beispiel TT.MM.JJJJ (z.B. &quot;31.12.1999&quot;)',
9358	email: 'Geben Sie bitte eine g&uuml;ltige E-Mail Adresse ein. Wie zum Beispiel &quot;[email protected]&quot;.',
9359	url: 'Geben Sie bitte eine g&uuml;ltige URL ein. Wie zum Beispiel http://www.example.com.',
9360	currencyDollar: 'Geben Sie bitte einen g&uuml;ltigen Betrag in Schweizer Franken ein. Wie zum Beispiel 100.00 CHF .',
9361	oneRequired: 'Machen Sie f&uuml;r mindestens eines der Eingabefelder einen Eintrag.',
9362	errorPrefix: 'Fehler: ',
9363	warningPrefix: 'Warnung: ',
9364
9365	// Form.Validator.Extras
9366	noSpace: 'In diesem Eingabefeld darf kein Leerzeichen sein.',
9367	reqChkByNode: 'Es wurden keine Elemente gew&auml;hlt.',
9368	requiredChk: 'Dieses Feld ist obligatorisch.',
9369	reqChkByName: 'Bitte w&auml;hlen Sie ein {label}.',
9370	match: 'Dieses Eingabefeld muss mit dem Feld {matchName} &uuml;bereinstimmen.',
9371	startDate: 'Das Anfangsdatum',
9372	endDate: 'Das Enddatum',
9373	currentDate: 'Das aktuelle Datum',
9374	afterDate: 'Das Datum sollte zur gleichen Zeit oder sp&auml;ter sein {label}.',
9375	beforeDate: 'Das Datum sollte zur gleichen Zeit oder fr&uuml;her sein {label}.',
9376	startMonth: 'W&auml;hlen Sie bitte einen Anfangsmonat',
9377	sameMonth: 'Diese zwei Datumsangaben m&uuml;ssen im selben Monat sein - Sie m&uuml;ssen eine von beiden ver&auml;ndern.',
9378	creditcard: 'Die eingegebene Kreditkartennummer ist ung&uuml;ltig. Bitte &uuml;berpr&uuml;fen Sie diese und versuchen Sie es erneut. {length} Zahlen eingegeben.'
9379
9380}
9380);
9381
9382/*
9383---
9384name: Locale.de-CH.Number
9385description: Number messages for Switzerland.
9386license: MIT-style license
9387authors:
9388  - Kim D. Jeker
9389requires:
9390  - Locale
9391  - Locale.CH.Number
9392provides: [Locale.de-CH.Number]
9393...
9394*/
9395
9396Locale.define('de-CH').inherit('CH', 'Number');
9397
9398/*
9399---
9400
9401name: Locale.de-DE.Form.Validator
9402
9403description: Form Validator messages for German.
9404
9405license: MIT-style license
9406
9407authors:
9408  - Frank Rossi
9409  - Ulrich Petri
9410  - Fabian Beiner
9411
9412requires:
9413  - Locale
9414
9415provides: [Locale.de-DE.Form.Validator]
9416
9417...
9418*/
9419
9420Locale.define('de-DE', 'FormValidator', {
9421
9422	required: 'Dieses Eingabefeld muss ausgefüllt werden.',
9423	minLength: 'Geben Sie bitte mindestens {minLength} Zeichen ein (Sie haben nur {length} Zeichen eingegeben).',
9424	maxLength: 'Geben Sie bitte nicht mehr als {maxLength} Zeichen ein (Sie haben {length} Zeichen eingegeben).',
9425	integer: 'Geben Sie in diesem Eingabefeld bitte eine ganze Zahl ein. Dezimalzahlen (z.B. "1.25") sind nicht erlaubt.',
9426	numeric: 'Geben Sie in diesem Eingabefeld bitte nur Zahlenwerte (z.B. "1", "1.1", "-1" oder "-1.1") ein.',
9427	digits: 'Geben Sie in diesem Eingabefeld bitte nur Zahlen und Satzzeichen ein (z.B. eine Telefonnummer mit Bindestrichen und Punkten ist erlaubt).',
9428	alpha: 'Geben Sie in diesem Eingabefeld bitte nur Buchstaben (a-z) ein. Leerzeichen und andere Zeichen sind nicht erlaubt.',
9429	alphanum: 'Geben Sie in diesem Eingabefeld bitte nur Buchstaben (a-z) und Zahlen (0-9) ein. Leerzeichen oder andere Zeichen sind nicht erlaubt.',
9430	dateSuchAs: 'Geben Sie bitte ein gültiges Datum ein (z.B. "{date}").',
9431	dateInFormatMDY: 'Geben Sie bitte ein gültiges Datum im Format TT.MM.JJJJ ein (z.B. "31.12.1999").',
9432	email: 'Geben Sie bitte eine gültige E-Mail-Adresse ein (z.B. "[email protected]").',
9433	url: 'Geben Sie bitte eine gültige URL ein (z.B. "http://www.example.com").',
9434	currencyDollar: 'Geben Sie bitte einen gültigen Betrag in EURO ein (z.B. 100.00€).',
9435	oneRequired: 'Bitte füllen Sie mindestens ein Eingabefeld aus.',
9436	errorPrefix: 'Fehler: ',
9437	warningPrefix: 'Warnung: ',
9438
9439	// Form.Validator.Extras
9440	noSpace: 'Es darf kein Leerzeichen in diesem Eingabefeld sein.',
9441	reqChkByNode: 'Es wurden keine Elemente gewählt.',
9442	requiredChk: 'Dieses Feld muss ausgefüllt werden.',
9443	reqChkByName: 'Bitte wählen Sie ein {label}.',
9444	match: 'Dieses Eingabefeld muss mit dem {matchName} Eingabefeld übereinstimmen.',
9445	startDate: 'Das Anfangsdatum',
9446	endDate: 'Das Enddatum',
9447	currentDate: 'Das aktuelle Datum',
9448	afterDate: 'Das Datum sollte zur gleichen Zeit oder später sein als {label}.',
9449	beforeDate: 'Das Datum sollte zur gleichen Zeit oder früher sein als {label}.',
9450	startMonth: 'Wählen Sie bitte einen Anfangsmonat',
9451	sameMonth: 'Diese zwei Datumsangaben müssen im selben Monat sein - Sie müssen eines von beiden verändern.',
9452	creditcard: 'Die eingegebene Kreditkartennummer ist ungültig. Bitte überprüfen Sie diese und versuchen Sie es erneut. {length} Zahlen eingegeben.'
9453
9454});
9455
9456/*
9457---
9458
9459name: Locale.de-DE.Number
9460
9461description: Number messages for German.
9462
9463license: MIT-style license
9464
9465authors:
9466  - Christoph Pojer
9467
9468requires:
9469  - Locale
9470  - Locale.EU.Number
9471
9472provides: [Locale.de-DE.Number]
9473
9474...
9475*/
9476
9477Locale.define('de-DE').inherit('EU', 'Number');
9478
9479/*
9480---
9481
9482name: Locale.el-GR.Date
9483
9484description: Date messages for Greek language.
9485
9486license: MIT-style license
9487
9488authors:
9489  - Periklis Argiriadis
9490
9491requires:
9492  - Locale
9493
9494provides: [Locale.el-GR.Date]
9495
9496...
9497*/
9498
9499Locale.define('el-GR', 'Date', {
9500
9501	months: ['Ιανουάριος', 'Φεβρουάριος', 'Μάρτιος', 'Απρίλιος', 'Μάιος', 'Ιούνιος', 'Ιούλιος', 'Αύγουστος', 'Σεπτέμβριος', 'Οκτώβριος', 'Νοέμβριος', 'Δεκέμβριος'],
9502	months_abbr: ['Ιαν', 'Φεβ', 'Μαρ', 'Απρ', 'Μάι', 'Ιουν', 'Ιουλ', 'Αυγ', 'Σεπ', 'Οκτ', 'Νοε', 'Δεκ'],
9503	days: ['Κυριακή', 'Δευτέρα', 'Τρίτη', 'Τετάρτη', 'Πέμπτη', 'Παρασκευή', 'Σάββατο'],
9504	days_abbr: ['Κυρ', 'Δευ', 'Τρι', 'Τετ', 'Πεμ', 'Παρ', 'Σαβ'],
9505
9506	// Culture's date order: DD/MM/YYYY
9507	dateOrder: ['date', 'month', 'year'],
9508	shortDate: '%d/%m/%Y',
9509	shortTime: '%I:%M%p',
9510	AM: 'πμ',
9511	PM: 'μμ',
9512	firstDayOfWeek: 1,
9513
9514	// Date.Extras
9515	ordinal: function(dayOfMonth){
9516		// 1st, 2nd, 3rd, etc.
9517		return (dayOfMonth > 3 && dayOfMonth < 21) ? 'ος' : ['ος'][Math.min(dayOfMonth % 10, 4)];
9518	},
9519
9520	lessThanMinuteAgo: 'λιγότερο από ένα λεπτό πριν',
9521	minuteAgo: 'περίπου ένα λεπτό πριν',
9522	minutesAgo: '{delta} λεπτά πριν',
9523	hourAgo: 'περίπου μια ώρα πριν',
9524	hoursAgo: 'περίπου {delta} ώρες πριν',
9525	dayAgo: '1 ημέρα πριν',
9526	daysAgo: '{delta} ημέρες πριν',
9527	weekAgo: '1 εβδομάδα πριν',
9528	weeksAgo: '{delta} εβδομάδες πριν',
9529	monthAgo: '1 μήνα πριν',
9530	monthsAgo: '{delta} μήνες πριν',
9531	yearAgo: '1 χρόνο πριν',
9532	yearsAgo: '{delta} χρόνια πριν',
9533
9534	lessThanMinuteUntil: 'λιγότερο από λεπτό από τώρα',
9535	minuteUntil: 'περίπου ένα λεπτό από τώρα',
9536	minutesUntil: '{delta} λεπτά από τώρα',
9537	hourUntil: 'περίπου μια ώρα από τώρα',
9538	hoursUntil: 'περίπου {delta} ώρες από τώρα',
9539	dayUntil: '1 ημέρα από τώρα',
9540	daysUntil: '{delta} ημέρες από τώρα',
9541	weekUntil: '1 εβδομάδα από τώρα',
9542	weeksUntil: '{delta} εβδομάδες από τώρα',
9543	monthUntil: '1 μήνας από τώρα',
9544	monthsUntil: '{delta} μήνες από τώρα',
9545	yearUntil: '1 χρόνος από τώρα',
9546	yearsUntil: '{delta} χρόνια από τώρα'
9547
9548});
9549
9550/*
9551---
9552
9553name: Locale.el-GR.Form.Validator
9554
9555description: Form Validator messages for Greek language.
9556
9557license: MIT-style license
9558
9559authors:
9560  - Dimitris Tsironis
9561
9562requires:
9563  - Locale
9564
9565provides: [Locale.el-GR.Form.Validator]
9566
9567...
9568*/
9569
9570Locale.define('el-GR', 'FormValidator', {
9571
9572	required: 'Αυτό το πεδίο είναι απαραίτητο.',
9573	length: 'Παρακαλούμε, εισάγετε {length} χαρακτήρες (έχετε ήδη εισάγει {elLength} χαρακτήρες).',
9574	minLength: 'Παρακαλούμε, εισάγετε τουλάχιστον {minLength} χαρακτήρες (έχετε ήδη εισάγε {length} χαρακτήρες).',
9575	maxlength: 'Παρακαλούμε, εισάγετε εώς {maxlength} χαρακτήρες (έχετε ήδη εισάγε {length} χαρακτήρες).',
9576	integer: 'Παρακαλούμε, εισάγετε έναν ακέραιο αριθμό σε αυτό το πεδίο. Οι αριθμοί με δεκαδικά ψηφία (π.χ. 1.25) δεν επιτρέπονται.',
9577	numeric: 'Παρακαλούμε, εισάγετε μόνο αριθμητικές τιμές σε αυτό το πεδίο (π.χ." 1 " ή " 1.1 " ή " -1 " ή " -1.1 " ).',
9578	digits: 'Παρακαλούμε, χρησιμοποιήστε μόνο αριθμούς και σημεία στίξης σε αυτόν τον τομέα (π.χ. επιτρέπεται αριθμός τηλεφώνου με παύλες ή τελείες).',
9579	alpha: 'Παρακαλούμε, χρησιμοποιήστε μόνο γράμματα (a-z) σε αυτό το πεδίο. Δεν επιτρέπονται κενά ή άλλοι χαρακτήρες.',
9580	alphanum: 'Παρακαλούμε, χρησιμοποιήστε μόνο γράμματα (a-z) ή αριθμούς (0-9) σε αυτόν τον τομέα. Δεν επιτρέπονται κενά ή άλλοι χαρακτήρες.',
9581	dateSuchAs: 'Παρακαλούμε, εισάγετε μια έγκυρη ημερομηνία, όπως {date}',
9582	dateInFormatMDY: 'Παρακαλώ εισάγετε μια έγκυρη ημερομηνία, όπως ΜΜ/ΗΗ/ΕΕΕΕ (π.χ. "12/31/1999").',
9583	email: 'Παρακαλούμε, εισάγετε μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου (π.χ. "[email protected]").',
9584	url: 'Παρακαλούμε, εισάγετε μια έγκυρη URL διεύθυνση, όπως http://www.example.com',
9585	currencyDollar: 'Παρακαλούμε, εισάγετε ένα έγκυρο ποσό σε δολλάρια (π.χ. $100.00).',
9586	oneRequired: 'Παρακαλούμε, εισάγετε κάτι για τουλάχιστον ένα από αυτά τα πεδία.',
9587	errorPrefix: 'Σφάλμα: ',
9588	warningPrefix: 'Προσοχή: ',
9589
9590	// Form.Validator.Extras
9591	noSpace: 'Δεν επιτρέπονται τα κενά σε αυτό το πεδίο.',
9592	reqChkByNode: 'Δεν έχει επιλεγεί κάποιο αντικείμενο',
9593	requiredChk: 'Αυτό το πεδίο είναι απαραίτητο.',
9594	reqChkByName: 'Παρακαλούμε, επιλέξτε μια ετικέτα {label}.',
9595	match: 'Αυτό το πεδίο πρέπει να ταιριάζει με το πεδίο {matchName}.',
9596	startDate: 'η ημερομηνία έναρξης',
9597	endDate: 'η ημερομηνία λήξης',
9598	currentDate: 'η τρέχουσα ημερομηνία',
9599	afterDate: 'Η ημερομηνία πρέπει να είναι η ίδια ή μετά από την {label}.',
9600	beforeDate: 'Η ημερομηνία πρέπει να είναι η ίδια ή πριν από την {label}.',
9601	startMonth: 'Παρακαλώ επιλέξτε ένα μήνα αρχής.',
9602	sameMonth: 'Αυτές οι δύο ημερομηνίες πρέπει να έχουν τον ίδιο μήνα - θα πρέπει να αλλάξετε ή το ένα ή το άλλο',
9603	creditcard: 'Ο αριθμός της πιστωτικής κάρτας δεν είναι έγκυρος. Παρακαλούμε ελέγξτε τον αριθμό και δοκιμάστε ξανά. {length} μήκος ψηφίων.'
9604
9605});
9606
9607/*
9608---
9609
9610name: Locale.en-GB.Date
9611
9612description: Date messages for British English.
9613
9614license: MIT-style license
9615
9616authors:
9617  - Aaron Newton
9618
9619requires:
9620  - Locale
9621  - Locale.en-US.Date
9622
9623provides: [Locale.en-GB.Date]
9624
9625...
9626*/
9627
9628Locale.define('en-GB', 'Date', {
9629
9630	// Culture's date order: DD/MM/YYYY
9631	dateOrder: ['date', 'month', 'year'],
9632	shortDate: '%d/%m/%Y',
9633	shortTime: '%H:%M'
9634
9635}).inherit('en-US', 'Date');
9636
9637/*
9638---
9639
9640name: Locale.en-US.Number
9641
9642description: Number messages for US English.
9643
9644license: MIT-style license
9645
9646authors:
9647  - Arian Stolwijk
9648
9649requires:
9650  - Locale
9651
9652provides: [Locale.en-US.Number]
9653
9654...
9655*/
9656
9657Locale.define('en-US', 'Number', {
9658
9659	decimal: '.',
9660	group: ',',
9661
9662/* 	Commented properties are the defaults for Number.format
9663	decimals: 0,
9664	precision: 0,
9665	scientific: null,
9666
9667	prefix: null,
9668	suffic: null,
9669
9670	// Negative/Currency/percentage will mixin Number
9671	negative: {
9672		prefix: '-'
9673	},*/
9674
9675	currency: {
9676//		decimals: 2,
9677		prefix: '$ '
9678	}/*,
9679
9680	percentage: {
9681		decimals: 2,
9682		suffix: '%'
9683	}*/
9684
9685});
9686
9687
9688
9689/*
9690---
9691
9692name: Locale.es-ES.Date
9693
9694description: Date messages for Spanish.
9695
9696license: MIT-style license
9697
9698authors:
9699  - Ãlfons Sanchez
9700
9701requires:
9702  - Locale
9703
9704provides: [Locale.es-ES.Date]
9705
9706...
9707*/
9708
9709Locale.define('es-ES', 'Date', {
9710
9711	months: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'],
9712	months_abbr: ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic'],
9713	days: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'],
9714	days_abbr: ['dom', 'lun', 'mar', 'mié', 'juv', 'vie', 'sáb'],
9715
9716	// Culture's date order: DD/MM/YYYY
9717	dateOrder: ['date', 'month', 'year'],
9718	shortDate: '%d/%m/%Y',
9719	shortTime: '%H:%M',
9720	AM: 'AM',
9721	PM: 'PM',
9722	firstDayOfWeek: 1,
9723
9724	// Date.Extras
9725	ordinal: '',
9726
9727	lessThanMinuteAgo: 'hace menos de un minuto',
9728	minuteAgo: 'hace un minuto',
9729	minutesAgo: 'hace {delta} minutos',
9730	hourAgo: 'hace una hora',
9731	hoursAgo: 'hace unas {delta} horas',
9732	dayAgo: 'hace un día',
9733	daysAgo: 'hace {delta} días',
9734	weekAgo: 'hace una semana',
9735	weeksAgo: 'hace unas {delta} semanas',
9736	monthAgo: 'hace un mes',
9737	monthsAgo: 'hace {delta} meses',
9738	yearAgo: 'hace un año',
9739	yearsAgo: 'hace {delta} años',
9740
9741	lessThanMinuteUntil: 'menos de un minuto desde ahora',
9742	minuteUntil: 'un minuto desde ahora',
9743	minutesUntil: '{delta} minutos desde ahora',
9744	hourUntil: 'una hora desde ahora',
9745	hoursUntil: 'unas {delta} horas desde ahora',
9746	dayUntil: 'un día desde ahora',
9747	daysUntil: '{delta} días desde ahora',
9748	weekUntil: 'una semana desde ahora',
9749	weeksUntil: 'unas {delta} semanas desde ahora',
9750	monthUntil: 'un mes desde ahora',
9751	monthsUntil: '{delta} meses desde ahora',
9752	yearUntil: 'un año desde ahora',
9753	yearsUntil: '{delta} años desde ahora'
9754
9755});
9756
9757/*
9758---
9759
9760name: Locale.es-AR.Date
9761
9762description: Date messages for Spanish (Argentina).
9763
9764license: MIT-style license
9765
9766authors:
9767  - Ãlfons Sanchez
9768  - Diego Massanti
9769
9770requires:
9771  - Locale
9772  - Locale.es-ES.Date
9773
9774provides: [Locale.es-AR.Date]
9775
9776...
9777*/
9778
9779Locale.define('es-AR').inherit('es-ES', 'Date');
9780
9781/*
9782---
9783
9784name: Locale.es-AR.Form.Validator
9785
9786description: Form Validator messages for Spanish (Argentina).
9787
9788license: MIT-style license
9789
9790authors:
9791  - Diego Massanti
9792
9793requires:
9794  - Locale
9795
9796provides: [Locale.es-AR.Form.Validator]
9797
9798...
9799*/
9800
9801Locale.define('es-AR', 'FormValidator', {
9802
9803	required: 'Este campo es obligatorio.',
9804	minLength: 'Por favor ingrese al menos {minLength} caracteres (ha ingresado {length} caracteres).',
9805	maxLength: 'Por favor no ingrese más de {maxLength} caracteres (ha ingresado {length} caracteres).',
9806	integer: 'Por favor ingrese un número entero en este campo. Números con decimales (p.e. 1,25) no se permiten.',
9807	numeric: 'Por favor ingrese solo valores numéricos en este campo (p.e. "1" o "1,1" o "-1" o "-1,1").',
9808	digits: 'Por favor use sólo números y puntuación en este campo (por ejemplo, un número de teléfono con guiones y/o puntos no está permitido).',
9809	alpha: 'Por favor use sólo letras (a-z) en este campo. No se permiten espacios ni otros caracteres.',
9810	alphanum: 'Por favor, usa sólo letras (a-z) o números (0-9) en este campo. No se permiten espacios u otros caracteres.',
9811	dateSuchAs: 'Por favor ingrese una fecha válida como {date}',
9812	dateInFormatMDY: 'Por favor ingrese una fecha válida, utulizando el formato DD/MM/YYYY (p.e. "31/12/1999")',
9813	email: 'Por favor, ingrese una dirección de e-mail válida. Por ejemplo, "[email protected]".',
9814	url: 'Por favor ingrese una URL válida como http://www.example.com.',
9815	currencyDollar: 'Por favor ingrese una cantidad válida de pesos. Por ejemplo $100,00 .',
9816	oneRequired: 'Por favor ingrese algo para por lo menos una de estas entradas.',
9817	errorPrefix: 'Error: ',
9818	warningPrefix: 'Advertencia: ',
9819
9820	// Form.Validator.Extras
9821	noSpace: 'No se permiten espacios en este campo.',
9822	reqChkByNode: 'No hay elementos seleccionados.',
9823	requiredChk: 'Este campo es obligatorio.',
9824	reqChkByName: 'Por favor selecciona una {label}.',
9825	match: 'Este campo necesita coincidir con el campo {matchName}',
9826	startDate: 'la fecha de inicio',
9827	endDate: 'la fecha de fin',
9828	currentDate: 'la fecha actual',
9829	afterDate: 'La fecha debe ser igual o posterior a {label}.',
9830	beforeDate: 'La fecha debe ser igual o anterior a {label}.',
9831	startMonth: 'Por favor selecciona un mes de origen',
9832	sameMonth: 'Estas dos fechas deben estar en el mismo mes - debes cambiar una u otra.'
9833
9834});
9835
9836/*
9837---
9838
9839name: Locale.es-AR.Number
9840
9841description: Number messages for es Argentina.
9842
9843license: MIT-style license
9844
9845authors:
9846  - Oscar Kuchuk
9847
9848requires:
9849  - Locale
9850
9851provides: [Locale.es-AR.Number]
9852
9853...
9854*/
9855
9856Locale.define('es-AR', 'Number', {
9857
9858	decimal: ',',
9859	group: '.',
9860
9861/* 	Commented properties are the defaults for Number.format
9862	decimals: 0,
9863	precision: 0,
9864	scientific: null,
9865
9866	prefix: null,
9867	suffic: null,
9868
9869	// Negative/Currency/percentage will mixin Number
9870	negative: {
9871		prefix: '-'
9872	},*/
9873
9874	currency: {
9875		decimals: 2,
9876		prefix: '$ '
9877	}/*,
9878
9879	percentage: {
9880		decimals: 2,
9881		suffix: '%'
9882	}*/
9883
9884});
9885
9886
9887/*
9888---
9889
9890name: Locale.es-ES.Form.Validator
9891
9892description: Form Validator messages for Spanish.
9893
9894license: MIT-style license
9895
9896authors:
9897  - Ãlfons Sanchez
9898
9899requires:
9900  - Locale
9901
9902provides: [Locale.es-ES.Form.Validator]
9903
9904...
9905*/
9906
9907Locale.define('es-ES', 'FormValidator', {
9908
9909	required: 'Este campo es obligatorio.',
9910	minLength: 'Por favor introduce al menos {minLength} caracteres (has introducido {length} caracteres).',
9911	maxLength: 'Por favor introduce no m&aacute;s de {maxLength} caracteres (has introducido {length} caracteres).',
9912	integer: 'Por favor introduce un n&uacute;mero entero en este campo. N&uacute;meros con decimales (p.e. 1,25) no se permiten.',
9913	numeric: 'Por favor introduce solo valores num&eacute;ricos en este campo (p.e. "1" o "1,1" o "-1" o "-1,1").',
9914	digits: 'Por favor usa solo n&uacute;meros y puntuaci&oacute;n en este campo (por ejemplo, un n&uacute;mero de tel&eacute;fono con guiones y puntos no esta permitido).',
9915	alpha: 'Por favor usa letras solo (a-z) en este campo. No se admiten espacios ni otros caracteres.',
9916	alphanum: 'Por favor, usa solo letras (a-z) o n&uacute;meros (0-9) en este campo. No se admiten espacios ni otros caracteres.',
9917	dateSuchAs: 'Por favor introduce una fecha v&aacute;lida como {date}',
9918	dateInFormatMDY: 'Por favor introduce una fecha v&aacute;lida como DD/MM/YYYY (p.e. "31/12/1999")',
9919	email: 'Por favor, introduce una direcci&oacute;n de email v&aacute;lida. Por ejemplo, "[email protected]".',
9920	url: 'Por favor introduce una URL v&aacute;lida como http://www.example.com.',
9921	currencyDollar: 'Por favor introduce una cantidad v&aacute;lida de €. Por ejemplo €100,00 .',
9922	oneRequired: 'Por favor introduce algo para por lo menos una de estas entradas.',
9923	errorPrefix: 'Error: ',
9924	warningPrefix: 'Aviso: ',
9925
9926	// Form.Validator.Extras
9927	noSpace: 'No pueden haber espacios en esta entrada.',
9928	reqChkByNode: 'No hay elementos seleccionados.',
9929	requiredChk: 'Este campo es obligatorio.',
9930	reqChkByName: 'Por favor selecciona una {label}.',
9931	match: 'Este campo necesita coincidir con el campo {matchName}',
9932	startDate: 'la fecha de inicio',
9933	endDate: 'la fecha de fin',
9934	currentDate: 'la fecha actual',
9935	afterDate: 'La fecha debe ser igual o posterior a {label}.',
9936	beforeDate: 'La fecha debe ser igual o anterior a {label}.',
9937	startMonth: 'Por favor selecciona un mes de origen',
9938	sameMonth: 'Estas dos fechas deben estar en el mismo mes - debes cambiar una u otra.'
9939
9940});
9941
9942/*
9943---
9944
9945name: Locale.es-VE.Date
9946
9947description: Date messages for Spanish (Venezuela).
9948
9949license: MIT-style license
9950
9951authors:
9952  - Daniel Barreto
9953
9954requires:
9955  - Locale
9956  - Locale.es-ES.Date
9957
9958provides: [Locale.es-VE.Date]
9959
9960...
9961*/
9962
9963Locale.define('es-VE').inherit('es-ES', 'Date');
9964
9965/*
9966---
9967
9968name: Locale.es-VE.Form.Validator
9969
9970description: Form Validator messages for Spanish (Venezuela).
9971
9972license: MIT-style license
9973
9974authors:
9975  - Daniel Barreto
9976
9977requires:
9978  - Locale
9979  - Locale.es-ES.Form.Validator
9980
9981provides: [Locale.es-VE.Form.Validator]
9982
9983...
9984*/
9985
9986Locale.define('es-VE', 'FormValidator', {
9987
9988	digits: 'Por favor usa solo n&uacute;meros y puntuaci&oacute;n en este campo. Por ejemplo, un n&uacute;mero de tel&eacute;fono con guiones y puntos no esta permitido.',
9989	alpha: 'Por favor usa solo letras (a-z) en este campo. No se admiten espacios ni otros caracteres.',
9990	currencyDollar: 'Por favor introduce una cantidad v&aacute;lida de Bs. Por ejemplo Bs. 100,00 .',
9991	oneRequired: 'Por favor introduce un valor para por lo menos una de estas entradas.',
9992
9993	// Form.Validator.Extras
9994	startDate: 'La fecha de inicio',
9995	endDate: 'La fecha de fin',
9996	currentDate: 'La fecha actual'
9997
9998}).inherit('es-ES', 'FormValidator');
9999
10000/*
10001---
10002
10003name: Locale.es-VE.Number
10004
10005description: Number messages for Spanish (Venezuela).
10006
10007license: MIT-style license
10008
10009authors:
10010  - Daniel Barreto
10011
10012requires:
10013  - Locale
10014
10015provides: [Locale.es-VE.Number]
10016
10017...
10018*/
10019
10020Locale.define('es-VE', 'Number', {
10021
10022	decimal: ',',
10023	group: '.',
10024/*
10025	decimals: 0,
10026	precision: 0,
10027*/
10028	// Negative/Currency/percentage will mixin Number
10029	negative: {
10030		prefix: '-'
10031	},
10032
10033	currency: {
10034		decimals: 2,
10035		prefix: 'Bs. '
10036	},
10037
10038	percentage: {
10039		decimals: 2,
10040		suffix: '%'
10041	}
10042
10043});
10044
10045/*
10046---
10047
10048name: Locale.et-EE.Date
10049
10050description: Date messages for Estonian.
10051
10052license: MIT-style license
10053
10054authors:
10055  - Kevin Valdek
10056
10057requires:
10058  - Locale
10059
10060provides: [Locale.et-EE.Date]
10061
10062...
10063*/
10064
10065Locale.define('et-EE', 'Date', {
10066
10067	months: ['jaanuar', 'veebruar', 'märts', 'aprill', 'mai', 'juuni', 'juuli', 'august', 'september', 'oktoober', 'november', 'detsember'],
10068	months_abbr: ['jaan', 'veebr', 'märts', 'apr', 'mai', 'juuni', 'juuli', 'aug', 'sept', 'okt', 'nov', 'dets'],
10069	days: ['pühapäev', 'esmaspäev', 'teisipäev', 'kolmapäev', 'neljapäev', 'reede', 'laupäev'],
10070	days_abbr: ['pühap', 'esmasp', 'teisip', 'kolmap', 'neljap', 'reede', 'laup'],
10071
10072	// Culture's date order: MM.DD.YYYY
10073	dateOrder: ['month', 'date', 'year'],
10074	shortDate: '%m.%d.%Y',
10075	shortTime: '%H:%M',
10076	AM: 'AM',
10077	PM: 'PM',
10078	firstDayOfWeek: 1,
10079
10080	// Date.Extras
10081	ordinal: '',
10082
10083	lessThanMinuteAgo: 'vähem kui minut aega tagasi',
10084	minuteAgo: 'umbes minut aega tagasi',
10085	minutesAgo: '{delta} minutit tagasi',
10086	hourAgo: 'umbes tund aega tagasi',
10087	hoursAgo: 'umbes {delta} tundi tagasi',
10088	dayAgo: '1 päev tagasi',
10089	daysAgo: '{delta} päeva tagasi',
10090	weekAgo: '1 nädal tagasi',
10091	weeksAgo: '{delta} nädalat tagasi',
10092	monthAgo: '1 kuu tagasi',
10093	monthsAgo: '{delta} kuud tagasi',
10094	yearAgo: '1 aasta tagasi',
10095	yearsAgo: '{delta} aastat tagasi',
10096
10097	lessThanMinuteUntil: 'vähem kui minuti aja pärast',
10098	minuteUntil: 'umbes minuti aja pärast',
10099	minutesUntil: '{delta} minuti pärast',
10100	hourUntil: 'umbes tunni aja pärast',
10101	hoursUntil: 'umbes {delta} tunni pärast',
10102	dayUntil: '1 päeva pärast',
10103	daysUntil: '{delta} päeva pärast',
10104	weekUntil: '1 nädala pärast',
10105	weeksUntil: '{delta} nädala pärast',
10106	monthUntil: '1 kuu pärast',
10107	monthsUntil: '{delta} kuu pärast',
10108	yearUntil: '1 aasta pärast',
10109	yearsUntil: '{delta} aasta pärast'
10110
10111});
10112
10113/*
10114---
10115
10116name: Locale.et-EE.Form.Validator
10117
10118description: Form Validator messages for Estonian.
10119
10120license: MIT-style license
10121
10122authors:
10123  - Kevin Valdek
10124
10125requires:
10126  - Locale
10127
10128provides: [Locale.et-EE.Form.Validator]
10129
10130...
10131*/
10132
10133Locale.define('et-EE', 'FormValidator', {
10134
10135	required: 'Väli peab olema täidetud.',
10136	minLength: 'Palun sisestage vähemalt {minLength} tähte (te sisestasite {length} tähte).',
10137	maxLength: 'Palun ärge sisestage rohkem kui {maxLength} tähte (te sisestasite {length} tähte).',
10138	integer: 'Palun sisestage väljale täisarv. Kümnendarvud (näiteks 1.25) ei ole lubatud.',
10139	numeric: 'Palun sisestage ainult numbreid väljale (näiteks "1", "1.1", "-1" või "-1.1").',
10140	digits: 'Palun kasutage ainult numbreid ja kirjavahemärke (telefoninumbri sisestamisel on lubatud kasutada kriipse ja punkte).',
10141	alpha: 'Palun kasutage ainult tähti (a-z). Tühikud ja teised sümbolid on keelatud.',
10142	alphanum: 'Palun kasutage ainult tähti (a-z) või numbreid (0-9). Tühikud ja teised sümbolid on keelatud.',
10143	dateSuchAs: 'Palun sisestage kehtiv kuupäev kujul {date}',
10144	dateInFormatMDY: 'Palun sisestage kehtiv kuupäev kujul MM.DD.YYYY (näiteks: "12.31.1999").',
10145	email: 'Palun sisestage kehtiv e-maili aadress (näiteks: "[email protected]").',
10146	url: 'Palun sisestage kehtiv URL (näiteks: http://www.example.com).',
10147	currencyDollar: 'Palun sisestage kehtiv $ summa (näiteks: $100.00).',
10148	oneRequired: 'Palun sisestage midagi vähemalt ühele antud väljadest.',
10149	errorPrefix: 'Viga: ',
10150	warningPrefix: 'Hoiatus: ',
10151
10152	// Form.Validator.Extras
10153	noSpace: 'Väli ei tohi sisaldada tühikuid.',
10154	reqChkByNode: 'Ükski väljadest pole valitud.',
10155	requiredChk: 'Välja täitmine on vajalik.',
10156	reqChkByName: 'Palun valige üks {label}.',
10157	match: 'Väli peab sobima {matchName} väljaga',
10158	startDate: 'algkuupäev',
10159	endDate: 'lõppkuupäev',
10160	currentDate: 'praegune kuupäev',
10161	afterDate: 'Kuupäev peab olema võrdne või pärast {label}.',
10162	beforeDate: 'Kuupäev peab olema võrdne või enne {label}.',
10163	startMonth: 'Palun valige algkuupäev.',
10164	sameMonth: 'Antud kaks kuupäeva peavad olema samas kuus - peate muutma ühte kuupäeva.'
10165
10166});
10167
10168/*
10169---
10170
10171name: Locale.fa.Date
10172
10173description: Date messages for Persian.
10174
10175license: MIT-style license
10176
10177authors:
10178  - Amir Hossein Hodjaty Pour
10179
10180requires:
10181  - Locale
10182
10183provides: [Locale.fa.Date]
10184
10185...
10186*/
10187
10188Locale.define('fa', 'Date', {
10189
10190	months: ['ژانویه', 'فوریه', 'مارس', 'آپریل', 'مه', 'ژوئن', 'ژوئیه', 'آگوست', 'سپتامبر', 'اکتبر', 'نوامبر', 'دسامبر'],
10191	months_abbr: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'],
10192	days: ['یکشنبه', 'دوشنبه', 'سه شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه', 'شنبه'],
10193	days_abbr: ['ي', 'د', 'س', 'چ', 'پ', 'ج', 'ش'],
10194
10195	// Culture's date order: MM/DD/YYYY
10196	dateOrder: ['month', 'date', 'year'],
10197	shortDate: '%m/%d/%Y',
10198	shortTime: '%I:%M%p',
10199	AM: 'ق.ظ',
10200	PM: 'ب.ظ',
10201
10202	// Date.Extras
10203	ordinal: 'ام',
10204
10205	lessThanMinuteAgo: 'کمتر از یک دقیقه پیش',
10206	minuteAgo: 'حدود یک دقیقه پیش',
10207	minutesAgo: '{delta} دقیقه پیش',
10208	hourAgo: 'حدود یک ساعت پیش',
10209	hoursAgo: 'حدود {delta} ساعت پیش',
10210	dayAgo: '1 روز پیش',
10211	daysAgo: '{delta} روز پیش',
10212	weekAgo: '1 هفته پیش',
10213	weeksAgo: '{delta} هفته پیش',
10214	monthAgo: '1 ماه پیش',
10215	monthsAgo: '{delta} ماه پیش',
10216	yearAgo: '1 سال پیش',
10217	yearsAgo: '{delta} سال پیش',
10218
10219	lessThanMinuteUntil: 'کمتر از یک دقیقه از حالا',
10220	minuteUntil: 'حدود یک دقیقه از حالا',
10221	minutesUntil: '{delta} دقیقه از حالا',
10222	hourUntil: 'حدود یک ساعت از حالا',
10223	hoursUntil: 'حدود {delta} ساعت از حالا',
10224	dayUntil: '1 روز از حالا',
10225	daysUntil: '{delta} روز از حالا',
10226	weekUntil: '1 هفته از حالا',
10227	weeksUntil: '{delta} هفته از حالا',
10228	monthUntil: '1 ماه از حالا',
10229	monthsUntil: '{delta} ماه از حالا',
10230	yearUntil: '1 سال از حالا',
10231	yearsUntil: '{delta} سال از حالا'
10232
10233});
10234
10235/*
10236---
10237
10238name: Locale.fa.Form.Validator
10239
10240description: Form Validator messages for Persian.
10241
10242license: MIT-style license
10243
10244authors:
10245  - Amir Hossein Hodjaty Pour
10246
10247requires:
10248  - Locale
10249
10250provides: [Locale.fa.Form.Validator]
10251
10252...
10253*/
10254
10255Locale.define('fa', 'FormValidator', {
10256
10257	required: 'این فیلد الزامی است.',
10258	minLength: 'شما باید حداقل {minLength} حرف وارد کنید ({length} حرف وارد کرده اید).',
10259	maxLength: 'لطفا حداکثر {maxLength} حرف وارد کنید (شما {length} حرف وارد کرده اید).',
10260	integer: 'لطفا از عدد صحیح استفاده کنید. اعداد اعشاری (مانند 1.25) مجاز نیستند.',
10261	numeric: 'لطفا فقط داده عددی وارد کنید (مانند "1" یا "1.1" یا "1-" یا "1.1-").',
10262	digits: 'لطفا فقط از اعداد و علامتها در این فیلد استفاده کنید (برای مثال شماره تلفن با خط تیره و نقطه قابل قبول است).',
10263	alpha: 'لطفا فقط از حروف الفباء برای این بخش استفاده کنید. کاراکترهای دیگر و فاصله مجاز نیستند.',
10264	alphanum: 'لطفا فقط از حروف الفباء و اعداد در این بخش استفاده کنید. کاراکترهای دیگر و فاصله مجاز نیستند.',
10265	dateSuchAs: 'لطفا یک تاریخ معتبر مانند {date} وارد کنید.',
10266	dateInFormatMDY: 'لطفا یک تاریخ معتبر به شکل MM/DD/YYYY وارد کنید (مانند "12/31/1999").',
10267	email: 'لطفا یک آدرس ایمیل معتبر وارد کنید. برای مثال "[email protected]".',
10268	url: 'لطفا یک URL معتبر مانند http://www.example.com وارد کنید.',
10269	currencyDollar: 'لطفا یک محدوده معتبر برای این بخش وارد کنید مانند 100.00$ .',
10270	oneRequired: 'لطفا حداقل یکی از فیلدها را پر کنید.',
10271	errorPrefix: 'خطا: ',
10272	warningPrefix: 'هشدار: ',
10273
10274	// Form.Validator.Extras
10275	noSpace: 'استفاده از فاصله در این بخش مجاز نیست.',
10276	reqChkByNode: 'موردی انتخاب نشده است.',
10277	requiredChk: 'این فیلد الزامی است.',
10278	reqChkByName: 'لطفا یک {label} را انتخاب کنید.',
10279	match: 'این فیلد باید با فیلد {matchName} مطابقت داشته باشد.',
10280	startDate: 'تاریخ شروع',
10281	endDate: 'تاریخ پایان',
10282	currentDate: 'تاریخ کنونی',
10283	afterDate: 'تاریخ میبایست برابر یا بعد از {label} باشد',
10284	beforeDate: 'تاریخ میبایست برابر یا قبل از {label} باشد',
10285	startMonth: 'لطفا ماه شروع را انتخاب کنید',
10286	sameMonth: 'این دو تاریخ باید در یک ماه باشند - شما باید یکی یا هر دو را تغییر دهید.',
10287	creditcard: 'شماره کارت اعتباری که وارد کرده اید معتبر نیست. لطفا شماره را بررسی کنید و مجددا تلاش کنید. {length} رقم وارد شده است.'
10288
10289});
10290
10291/*
10292---
10293
10294name: Locale.fi-FI.Date
10295
10296description: Date messages for Finnish.
10297
10298license: MIT-style license
10299
10300authors:
10301  - ksel
10302
10303requires:
10304  - Locale
10305
10306provides: [Locale.fi-FI.Date]
10307
10308...
10309*/
10310
10311Locale.define('fi-FI', 'Date', {
10312
10313	// NOTE: months and days are not capitalized in finnish
10314	months: ['tammikuu', 'helmikuu', 'maaliskuu', 'huhtikuu', 'toukokuu', 'kesäkuu', 'heinäkuu', 'elokuu', 'syyskuu', 'lokakuu', 'marraskuu', 'joulukuu'],
10315
10316	// these abbreviations are really not much used in finnish because they obviously won't abbreviate very much. ;)
10317	// NOTE: sometimes one can see forms such as "tammi", "helmi", etc. but that is not proper finnish.
10318	months_abbr: ['tammik.', 'helmik.', 'maalisk.', 'huhtik.', 'toukok.', 'kesäk.', 'heinäk.', 'elok.', 'syysk.', 'lokak.', 'marrask.', 'jouluk.'],
10319
10320	days: ['sunnuntai', 'maanantai', 'tiistai', 'keskiviikko', 'torstai', 'perjantai', 'lauantai'],
10321	days_abbr: ['su', 'ma', 'ti', 'ke', 'to', 'pe', 'la'],
10322
10323	// Culture's date order: DD/MM/YYYY
10324	dateOrder: ['date', 'month', 'year'],
10325	shortDate: '%d.%m.%Y',
10326	shortTime: '%H:%M',
10327	AM: 'AM',
10328	PM: 'PM',
10329	firstDayOfWeek: 1,
10330
10331	// Date.Extras
10332	ordinal: '.',
10333
10334	lessThanMinuteAgo: 'vajaa minuutti sitten',
10335	minuteAgo: 'noin minuutti sitten',
10336	minutesAgo: '{delta} minuuttia sitten',
10337	hourAgo: 'noin tunti sitten',
10338	hoursAgo: 'noin {delta} tuntia sitten',
10339	dayAgo: 'päivä sitten',
10340	daysAgo: '{delta} päivää sitten',
10341	weekAgo: 'viikko sitten',
10342	weeksAgo: '{delta} viikkoa sitten',
10343	monthAgo: 'kuukausi sitten',
10344	monthsAgo: '{delta} kuukautta sitten',
10345	yearAgo: 'vuosi sitten',
10346	yearsAgo: '{delta} vuotta sitten',
10347
10348	lessThanMinuteUntil: 'vajaan minuutin kuluttua',
10349	minuteUntil: 'noin minuutin kuluttua',
10350	minutesUntil: '{delta} minuutin kuluttua',
10351	hourUntil: 'noin tunnin kuluttua',
10352	hoursUntil: 'noin {delta} tunnin kuluttua',
10353	dayUntil: 'päivän kuluttua',
10354	daysUntil: '{delta} päivän kuluttua',
10355	weekUntil: 'viikon kuluttua',
10356	weeksUntil: '{delta} viikon kuluttua',
10357	monthUntil: 'kuukauden kuluttua',
10358	monthsUntil: '{delta} kuukauden kuluttua',
10359	yearUntil: 'vuoden kuluttua',
10360	yearsUntil: '{delta} vuoden kuluttua'
10361
10362});
10363
10364/*
10365---
10366
10367name: Locale.fi-FI.Form.Validator
10368
10369description: Form Validator messages for Finnish.
10370
10371license: MIT-style license
10372
10373authors:
10374  - ksel
10375
10376requires:
10377  - Locale
10378
10379provides: [Locale.fi-FI.Form.Validator]
10380
10381...
10382*/
10383
10384Locale.define('fi-FI', 'FormValidator', {
10385
10386	required: 'Tämä kenttä on pakollinen.',
10387	minLength: 'Ole hyvä ja anna vähintään {minLength} merkkiä (annoit {length} merkkiä).',
10388	maxLength: 'Älä anna enempää kuin {maxLength} merkkiä (annoit {length} merkkiä).',
10389	integer: 'Ole hyvä ja anna kokonaisluku. Luvut, joissa on desimaaleja (esim. 1.25) eivät ole sallittuja.',
10390	numeric: 'Anna tähän kenttään lukuarvo (kuten "1" tai "1.1" tai "-1" tai "-1.1").',
10391	digits: 'Käytä pelkästään numeroita ja välimerkkejä tässä kentässä (syötteet, kuten esim. puhelinnumero, jossa on väliviivoja, pilkkuja tai pisteitä, kelpaa).',
10392	alpha: 'Anna tähän kenttään vain kirjaimia (a-z). Välilyönnit tai muut merkit eivät ole sallittuja.',
10393	alphanum: 'Anna tähän kenttään vain kirjaimia (a-z) tai numeroita (0-9). Välilyönnit tai muut merkit eivät ole sallittuja.',
10394	dateSuchAs: 'Ole hyvä ja anna kelvollinen päivmäärä, kuten esimerkiksi {date}',
10395	dateInFormatMDY: 'Ole hyvä ja anna kelvollinen päivämäärä muodossa pp/kk/vvvv (kuten "12/31/1999")',
10396	email: 'Ole hyvä ja anna kelvollinen sähköpostiosoite (kuten esimerkiksi "[email protected]").',
10397	url: 'Ole hyvä ja anna kelvollinen URL, kuten esimerkiksi http://www.example.com.',
10398	currencyDollar: 'Ole hyvä ja anna kelvollinen eurosumma (kuten esimerkiksi 100,00 EUR) .',
10399	oneRequired: 'Ole hyvä ja syötä jotakin ainakin johonkin näistä kentistä.',
10400	errorPrefix: 'Virhe: ',
10401	warningPrefix: 'Varoitus: ',
10402
10403	// Form.Validator.Extras
10404	noSpace: 'Tässä syötteessä ei voi olla välilyöntejä',
10405	reqChkByNode: 'Ei valintoja.',
10406	requiredChk: 'Tämä kenttä on pakollinen.',
10407	reqChkByName: 'Ole hyvä ja valitse {label}.',
10408	match: 'Tämän kentän tulee vastata kenttää {matchName}',
10409	startDate: 'alkupäivämäärä',
10410	endDate: 'loppupäivämäärä',
10411	currentDate: 'nykyinen päivämäärä',
10412	afterDate: 'Päivämäärän tulisi olla sama tai myöhäisempi ajankohta kuin {label}.',
10413	beforeDate: 'Päivämäärän tulisi olla sama tai aikaisempi ajankohta kuin {label}.',
10414	startMonth: 'Ole hyvä ja valitse aloituskuukausi',
10415	sameMonth: 'Näiden kahden päivämäärän tulee olla saman kuun sisällä -- sinun pitää muuttaa jompaa kumpaa.',
10416	creditcard: 'Annettu luottokortin numero ei kelpaa. Ole hyvä ja tarkista numero sekä yritä uudelleen. {length} numeroa syötetty.'
10417
10418});
10419
10420/*
10421---
10422
10423name: Locale.fi-FI.Number
10424
10425description: Finnish number messages
10426
10427license: MIT-style license
10428
10429authors:
10430  - ksel
10431
10432requires:
10433  - Locale
10434  - Locale.EU.Number
10435
10436provides: [Locale.fi-FI.Number]
10437
10438...
10439*/
10440
10441Locale.define('fi-FI', 'Number', {
10442
10443	group: ' ' // grouped by space
10444
10445}).inherit('EU', 'Number');
10446
10447/*
10448---
10449
10450name: Locale.fr-FR.Date
10451
10452description: Date messages for French.
10453
10454license: MIT-style license
10455
10456authors:
10457  - Nicolas Sorosac
10458  - Antoine Abt
10459
10460requires:
10461  - Locale
10462
10463provides: [Locale.fr-FR.Date]
10464
10465...
10466*/
10467
10468Locale.define('fr-FR', 'Date', {
10469
10470	months: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
10471	months_abbr: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'],
10472	days: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'],
10473	days_abbr: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],
10474
10475	// Culture's date order: DD/MM/YYYY
10476	dateOrder: ['date', 'month', 'year'],
10477	shortDate: '%d/%m/%Y',
10478	shortTime: '%H:%M',
10479	AM: 'AM',
10480	PM: 'PM',
10481	firstDayOfWeek: 1,
10482
10483	// Date.Extras
10484	ordinal: function(dayOfMonth){
10485		return (dayOfMonth > 1) ? '' : 'er';
10486	},
10487
10488	lessThanMinuteAgo: "il y a moins d'une minute",
10489	minuteAgo: 'il y a une minute',
10490	minutesAgo: 'il y a {delta} minutes',
10491	hourAgo: 'il y a une heure',
10492	hoursAgo: 'il y a {delta} heures',
10493	dayAgo: 'il y a un jour',
10494	daysAgo: 'il y a {delta} jours',
10495	weekAgo: 'il y a une semaine',
10496	weeksAgo: 'il y a {delta} semaines',
10497	monthAgo: 'il y a 1 mois',
10498	monthsAgo: 'il y a {delta} mois',
10499	yearthAgo: 'il y a 1 an',
10500	yearsAgo: 'il y a {delta} ans',
10501
10502	lessThanMinuteUntil: "dans moins d'une minute",
10503	minuteUntil: 'dans une minute',
10504	minutesUntil: 'dans {delta} minutes',
10505	hourUntil: 'dans une heure',
10506	hoursUntil: 'dans {delta} heures',
10507	dayUntil: 'dans un jour',
10508	daysUntil: 'dans {delta} jours',
10509	weekUntil: 'dans 1 semaine',
10510	weeksUntil: 'dans {delta} semaines',
10511	monthUntil: 'dans 1 mois',
10512	monthsUntil: 'dans {delta} mois',
10513	yearUntil: 'dans 1 an',
10514	yearsUntil: 'dans {delta} ans'
10515
10516});
10517
10518/*
10519---
10520
10521name: Locale.fr-FR.Form.Validator
10522
10523description: Form Validator messages for French.
10524
10525license: MIT-style license
10526
10527authors:
10528  - Miquel Hudin
10529  - Nicolas Sorosac
10530
10531requires:
10532  - Locale
10533
10534provides: [Locale.fr-FR.Form.Validator]
10535
10536...
10537*/
10538
10539/*eslint mootools-whitespace:0*/
10540
10541Locale.define('fr-FR', 'FormValidator', {
10542
10543	required: 'Ce champ est obligatoire.',
10544	length: 'Veuillez saisir {length} caract&egrave;re(s) (vous avez saisi {elLength} caract&egrave;re(s)',
10545	minLength: 'Veuillez saisir un minimum de {minLength} caract&egrave;re(s) (vous avez saisi {length} caract&egrave;re(s)).',
10546	maxLength: 'Veuillez saisir un maximum de {maxLength} caract&egrave;re(s) (vous avez saisi {length} caract&egrave;re(s)).',
10547	integer: 'Veuillez saisir un nombre entier dans ce champ. Les nombres d&eacute;cimaux (ex : "1,25") ne sont pas autoris&eacute;s.',
10548	numeric: 'Veuillez saisir uniquement des chiffres dans ce champ (ex : "1" ou "1,1" ou "-1" ou "-1,1").',
10549	digits: "Veuillez saisir uniquement des chiffres et des signes de ponctuation dans ce champ (ex : un num&eacute;ro de t&eacute;l&eacute;phone avec des traits d'union est autoris&eacute;).",
10550	alpha: 'Veuillez saisir uniquement des lettres (a-z) dans ce champ. Les espaces ou autres caract&egrave;res ne sont pas autoris&eacute;s.',
10551	alphanum: 'Veuillez saisir uniquement des lettres (a-z) ou des chiffres (0-9) dans ce champ. Les espaces ou autres caract&egrave;res ne sont pas autoris&eacute;s.',
10552	dateSuchAs: 'Veuillez saisir une date correcte comme {date}',
10553	dateInFormatMDY: 'Veuillez saisir une date correcte, au format JJ/MM/AAAA (ex : "31/11/1999").',
10554	email: 'Veuillez saisir une adresse de courrier &eacute;lectronique. Par exemple "[email protected]".',
10555	url: 'Veuillez saisir une URL, comme http://www.exemple.com.',
10556	currencyDollar: 'Veuillez saisir une quantit&eacute; correcte. Par exemple 100,00&euro;.',
10557	oneRequired: 'Veuillez s&eacute;lectionner au moins une de ces options.',
10558	errorPrefix: 'Erreur : ',
10559	warningPrefix: 'Attention : ',
10560
10561	// Form.Validator.Extras
10562	noSpace: "Ce champ n'accepte pas les espaces.",
10563	reqChkByNode: "Aucun &eacute;l&eacute;ment n'est s&eacute;lectionn&eacute;.",
10564	requiredChk: 'Ce champ est obligatoire.',
10565	reqChkByName: 'Veuillez s&eacute;lectionner un(e) {label}.',
10566	match: 'Ce champ doit correspondre avec le champ {matchName}.',
10567	startDate: 'date de d&eacute;but',
10568	endDate: 'date de fin',
10569	currentDate: 'date actuelle',
10570	afterDate: 'La date doit &ecirc;tre identique ou post&eacute;rieure &agrave; {label}.',
10571	beforeDate: 'La date doit &ecirc;tre identique ou ant&eacute;rieure &agrave; {label}.',
10572	startMonth: 'Veuillez s&eacute;lectionner un mois de d&eacute;but.',
10573	sameMonth: 'Ces deux dates doivent &ecirc;tre dans le m&ecirc;me mois - vous devez en modifier une.',
10574	creditcard: 'Le num&eacute;ro de carte de cr&eacute;dit est invalide. Merci de v&eacute;rifier le num&eacute;ro et de r&eacute;essayer. Vous avez entr&eacute; {length} chiffre(s).'
10575
10576}
10576);
10577
10578/*
10579---
10580
10581name: Locale.fr-FR.Number
10582
10583description: Number messages for French.
10584
10585license: MIT-style license
10586
10587authors:
10588  - Arian Stolwijk
10589  - sv1l
10590
10591requires:
10592  - Locale
10593  - Locale.EU.Number
10594
10595provides: [Locale.fr-FR.Number]
10596
10597...
10598*/
10599
10600Locale.define('fr-FR', 'Number', {
10601
10602	group: ' ' // In fr-FR localization, group character is a blank space
10603
10604}).inherit('EU', 'Number');
10605
10606/*
10607---
10608
10609name: Locale.he-IL.Date
10610
10611description: Date messages for Hebrew.
10612
10613license: MIT-style license
10614
10615authors:
10616  - Elad Ossadon
10617
10618requires:
10619  - Locale
10620
10621provides: [Locale.he-IL.Date]
10622
10623...
10624*/
10625
10626Locale.define('he-IL', 'Date', {
10627
10628	months: ['ינואר', 'פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר', 'דצמבר'],
10629	months_abbr: ['ינואר', 'פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר', 'דצמבר'],
10630	days: ['ראשון', 'שני', 'שלישי', 'רביעי', 'חמישי', 'שישי', 'שבת'],
10631	days_abbr: ['ראשון', 'שני', 'שלישי', 'רביעי', 'חמישי', 'שישי', 'שבת'],
10632
10633	// Culture's date order: MM/DD/YYYY
10634	dateOrder: ['date', 'month', 'year'],
10635	shortDate: '%d/%m/%Y',
10636	shortTime: '%H:%M',
10637	AM: 'AM',
10638	PM: 'PM',
10639	firstDayOfWeek: 0,
10640
10641	// Date.Extras
10642	ordinal: '',
10643
10644	lessThanMinuteAgo: 'לפני פחות מדקה',
10645	minuteAgo: 'לפני כדקה',
10646	minutesAgo: 'לפני {delta} דקות',
10647	hourAgo: 'לפני כשעה',
10648	hoursAgo: 'לפני {delta} שעות',
10649	dayAgo: 'לפני יום',
10650	daysAgo: 'לפני {delta} ימים',
10651	weekAgo: 'לפני שבוע',
10652	weeksAgo: 'לפני {delta} שבועות',
10653	monthAgo: 'לפני חודש',
10654	monthsAgo: 'לפני {delta} חודשים',
10655	yearAgo: 'לפני שנה',
10656	yearsAgo: 'לפני {delta} שנים',
10657
10658	lessThanMinuteUntil: 'בעוד פחות מדקה',
10659	minuteUntil: 'בעוד כדקה',
10660	minutesUntil: 'בעוד {delta} דקות',
10661	hourUntil: 'בעוד כשעה',
10662	hoursUntil: 'בעוד {delta} שעות',
10663	dayUntil: 'בעוד יום',
10664	daysUntil: 'בעוד {delta} ימים',
10665	weekUntil: 'בעוד שבוע',
10666	weeksUntil: 'בעוד {delta} שבועות',
10667	monthUntil: 'בעוד חודש',
10668	monthsUntil: 'בעוד {delta} חודשים',
10669	yearUntil: 'בעוד שנה',
10670	yearsUntil: 'בעוד {delta} שנים'
10671
10672});
10673
10674/*
10675---
10676
10677name: Locale.he-IL.Form.Validator
10678
10679description: Form Validator messages for Hebrew.
10680
10681license: MIT-style license
10682
10683authors:
10684  - Elad Ossadon
10685
10686requires:
10687  - Locale
10688
10689provides: [Locale.he-IL.Form.Validator]
10690
10691...
10692*/
10693
10694Locale.define('he-IL', 'FormValidator', {
10695
10696	required: 'נא למלא שדה זה.',
10697	minLength: 'נא להזין לפחות {minLength} תווים (הזנת {length} תווים).',
10698	maxLength: 'נא להזין עד {maxLength} תווים (הזנת {length} תווים).',
10699	integer: 'נא להזין מספר שלם לשדה זה. מספרים עשרוניים (כמו 1.25) אינם חוקיים.',
10700	numeric: 'נא להזין ערך מספרי בלבד בשדה זה (כמו "1", "1.1", "-1" או "-1.1").',
10701	digits: 'נא להזין רק ספרות וסימני הפרדה בשדה זה (למשל, מספר טלפון עם מקפים או נקודות הוא חוקי).',
10702	alpha: 'נא להזין רק אותיות באנגלית (a-z) בשדה זה. רווחים או תווים אחרים אינם חוקיים.',
10703	alphanum: 'נא להזין רק אותריות באנגלית (a-z) או ספרות (0-9) בשדה זה. אווחרים או תווים אחרים אינם חוקיים.',
10704	dateSuchAs: 'נא להזין תאריך חוקי, כמו {date}',
10705	dateInFormatMDY: 'נא להזין תאריך חוקי בפורמט MM/DD/YYYY (כמו "12/31/1999")',
10706	email: 'נא להזין כתובת אימייל חוקית. לדוגמה: "[email protected]".',
10707	url: 'נא להזין כתובת אתר חוקית, כמו http://www.example.com.',
10708	currencyDollar: 'נא להזין סכום דולרי חוקי. לדוגמה $100.00.',
10709	oneRequired: 'נא לבחור לפחות בשדה אחד.',
10710	errorPrefix: 'שגיאה: ',
10711	warningPrefix: 'אזהרה: ',
10712
10713	// Form.Validator.Extras
10714	noSpace: 'אין להזין רווחים בשדה זה.',
10715	reqChkByNode: 'נא לבחור אחת מהאפשרויות.',
10716	requiredChk: 'שדה זה נדרש.',
10717	reqChkByName: 'נא לבחור {label}.',
10718	match: 'שדה זה צריך להתאים לשדה {matchName}',
10719	startDate: 'תאריך ההתחלה',
10720	endDate: 'תאריך הסיום',
10721	currentDate: 'התאריך הנוכחי',
10722	afterDate: 'התאריך צריך להיות זהה או אחרי {label}.',
10723	beforeDate: 'התאריך צריך להיות זהה או לפני {label}.',
10724	startMonth: 'נא לבחור חודש התחלה',
10725	sameMonth: 'שני תאריכים אלה צריכים להיות באותו חודש - נא לשנות אחד התאריכים.',
10726	creditcard: 'מספר כרטיס האשראי שהוזן אינו חוקי. נא לבדוק שנית. הוזנו {length} ספרות.'
10727
10728});
10729
10730/*
10731---
10732
10733name: Locale.he-IL.Number
10734
10735description: Number messages for Hebrew.
10736
10737license: MIT-style license
10738
10739authors:
10740  - Elad Ossadon
10741
10742requires:
10743  - Locale
10744
10745provides: [Locale.he-IL.Number]
10746
10747...
10748*/
10749
10750Locale.define('he-IL', 'Number', {
10751
10752	decimal: '.',
10753	group: ',',
10754
10755	currency: {
10756		suffix: ' ₪'
10757	}
10758
10759});
10760
10761/*
10762---
10763
10764name: Locale.hu-HU.Date
10765
10766description: Date messages for Hungarian.
10767
10768license: MIT-style license
10769
10770authors:
10771  - Zsolt Szegheő
10772
10773requires:
10774  - Locale
10775
10776provides: [Locale.hu-HU.Date]
10777
10778...
10779*/
10780
10781Locale.define('hu-HU', 'Date', {
10782
10783	months: ['Január', 'Február', 'Március', 'Április', 'Május', 'Június', 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'],
10784	months_abbr: ['jan.', 'febr.', 'márc.', 'ápr.', 'máj.', 'jún.', 'júl.', 'aug.', 'szept.', 'okt.', 'nov.', 'dec.'],
10785	days: ['Vasárnap', 'Hétfő', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat'],
10786	days_abbr: ['V', 'H', 'K', 'Sze', 'Cs', 'P', 'Szo'],
10787
10788	// Culture's date order: YYYY.MM.DD.
10789	dateOrder: ['year', 'month', 'date'],
10790	shortDate: '%Y.%m.%d.',
10791	shortTime: '%I:%M',
10792	AM: 'de.',
10793	PM: 'du.',
10794	firstDayOfWeek: 1,
10795
10796	// Date.Extras
10797	ordinal: '.',
10798
10799	lessThanMinuteAgo: 'alig egy perce',
10800	minuteAgo: 'egy perce',
10801	minutesAgo: '{delta} perce',
10802	hourAgo: 'egy órája',
10803	hoursAgo: '{delta} órája',
10804	dayAgo: '1 napja',
10805	daysAgo: '{delta} napja',
10806	weekAgo: '1 hete',
10807	weeksAgo: '{delta} hete',
10808	monthAgo: '1 hónapja',
10809	monthsAgo: '{delta} hónapja',
10810	yearAgo: '1 éve',
10811	yearsAgo: '{delta} éve',
10812
10813	lessThanMinuteUntil: 'alig egy perc múlva',
10814	minuteUntil: 'egy perc múlva',
10815	minutesUntil: '{delta} perc múlva',
10816	hourUntil: 'egy óra múlva',
10817	hoursUntil: '{delta} óra múlva',
10818	dayUntil: '1 nap múlva',
10819	daysUntil: '{delta} nap múlva',
10820	weekUntil: '1 hét múlva',
10821	weeksUntil: '{delta} hét múlva',
10822	monthUntil: '1 hónap múlva',
10823	monthsUntil: '{delta} hónap múlva',
10824	yearUntil: '1 év múlva',
10825	yearsUntil: '{delta} év múlva'
10826
10827});
10828
10829/*
10830---
10831
10832name: Locale.hu-HU.Form.Validator
10833
10834description: Form Validator messages for Hungarian.
10835
10836license: MIT-style license
10837
10838authors:
10839  - Zsolt Szegheő
10840
10841requires:
10842  - Locale
10843
10844provides: [Locale.hu-HU.Form.Validator]
10845
10846...
10847*/
10848
10849/*eslint mootools-whitespace:0*/
10850
10851Locale.define('hu-HU', 'FormValidator', {
10852
10853	required: 'A mező kitöltése kötelező.',
10854	minLength: 'Legalább {minLength} karakter megadása szükséges (megadva {length} karakter).',
10855	maxLength: 'Legfeljebb {maxLength} karakter megadása lehetséges (megadva {length} karakter).',
10856	integer: 'Egész szám megadása szükséges. A tizedesjegyek (pl. 1.25) nem engedélyezettek.',
10857	numeric: 'Szám megadása szükséges (pl. "1" vagy "1.1" vagy "-1" vagy "-1.1").',
10858	digits: 'Csak számok és írásjelek megadása lehetséges (pl. telefonszám kötőjelek és/vagy perjelekkel).',
10859	alpha: 'Csak betűk (a-z) megadása lehetséges. Szóköz és egyéb karakterek nem engedélyezettek.',
10860	alphanum: 'Csak betűk (a-z) vagy számok (0-9) megadása lehetséges. Szóköz és egyéb karakterek nem engedélyezettek.',
10861	dateSuchAs: 'Valós dátum megadása szükséges (pl. {date}).',
10862	dateInFormatMDY: 'Valós dátum megadása szükséges ÉÉÉÉ.HH.NN. formában. (pl. "1999.12.31.")',
10863	email: 'Valós e-mail cím megadása szükséges (pl. "[email protected]").',
10864	url: 'Valós URL megadása szükséges (pl. http://www.example.com).',
10865	currencyDollar: 'Valós pénzösszeg megadása szükséges (pl. 100.00 Ft.).',
10866	oneRequired: 'Az alábbi mezők legalább egyikének kitöltése kötelező.',
10867	errorPrefix: 'Hiba: ',
10868	warningPrefix: 'Figyelem: ',
10869
10870	// Form.Validator.Extras
10871	noSpace: 'A mező nem tartalmazhat szóközöket.',
10872	reqChkByNode: 'Nincs egyetlen kijelölt elem sem.',
10873	requiredChk: 'A mező kitöltése kötelező.',
10874	reqChkByName: 'Egy {label} kiválasztása szükséges.',
10875	match: 'A mezőnek egyeznie kell a(z) {matchName} mezővel.',
10876	startDate: 'a kezdet dátuma',
10877	endDate: 'a vég dátuma',
10878	currentDate: 'jelenlegi dátum',
10879	afterDate: 'A dátum nem lehet kisebb, mint {label}.',
10880	beforeDate: 'A dátum nem lehet nagyobb, mint {label}.',
10881	startMonth: 'Kezdeti hónap megadása szükséges.',
10882	sameMonth: 'A két dátumnak ugyanazon hónapban kell lennie.',
10883	creditcard: 'A megadott bankkártyaszám nem valódi (megadva {length} számjegy).'
10884
10885});
10886
10887/*
10888---
10889
10890name: Locale.it-IT.Date
10891
10892description: Date messages for Italian.
10893
10894license: MIT-style license.
10895
10896authors:
10897  - Andrea Novero
10898  - Valerio Proietti
10899
10900requires:
10901  - Locale
10902
10903provides: [Locale.it-IT.Date]
10904
10905...
10906*/
10907
10908Locale.define('it-IT', 'Date', {
10909
10910	months: ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre'],
10911	months_abbr: ['gen', 'feb', 'mar', 'apr', 'mag', 'giu', 'lug', 'ago', 'set', 'ott', 'nov', 'dic'],
10912	days: ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'],
10913	days_abbr: ['dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab'],
10914
10915	// Culture's date order: DD/MM/YYYY
10916	dateOrder: ['date', 'month', 'year'],
10917	shortDate: '%d/%m/%Y',
10918	shortTime: '%H.%M',
10919	AM: 'AM',
10920	PM: 'PM',
10921	firstDayOfWeek: 1,
10922
10923	// Date.Extras
10924	ordinal: 'º',
10925
10926	lessThanMinuteAgo: 'meno di un minuto fa',
10927	minuteAgo: 'circa un minuto fa',
10928	minutesAgo: 'circa {delta} minuti fa',
10929	hourAgo: "circa un'ora fa",
10930	hoursAgo: 'circa {delta} ore fa',
10931	dayAgo: 'circa 1 giorno fa',
10932	daysAgo: 'circa {delta} giorni fa',
10933	weekAgo: 'una settimana fa',
10934	weeksAgo: '{delta} settimane fa',
10935	monthAgo: 'un mese fa',
10936	monthsAgo: '{delta} mesi fa',
10937	yearAgo: 'un anno fa',
10938	yearsAgo: '{delta} anni fa',
10939
10940	lessThanMinuteUntil: 'tra meno di un minuto',
10941	minuteUntil: 'tra circa un minuto',
10942	minutesUntil: 'tra circa {delta} minuti',
10943	hourUntil: "tra circa un'ora",
10944	hoursUntil: 'tra circa {delta} ore',
10945	dayUntil: 'tra circa un giorno',
10946	daysUntil: 'tra circa {delta} giorni',
10947	weekUntil: 'tra una settimana',
10948	weeksUntil: 'tra {delta} settimane',
10949	monthUntil: 'tra un mese',
10950	monthsUntil: 'tra {delta} mesi',
10951	yearUntil: 'tra un anno',
10952	yearsUntil: 'tra {delta} anni'
10953
10954});
10955
10956/*
10957---
10958
10959name: Locale.it-IT.Form.Validator
10960
10961description: Form Validator messages for Italian.
10962
10963license: MIT-style license
10964
10965authors:
10966  - Leonardo Laureti
10967  - Andrea Novero
10968
10969requires:
10970  - Locale
10971
10972provides: [Locale.it-IT.Form.Validator]
10973
10974...
10975*/
10976
10977/*eslint mootools-whitespace:0*/
10978
10979Locale.define('it-IT', 'FormValidator', {
10980
10981	required: 'Il campo &egrave; obbligatorio.',
10982	minLength: 'Inserire almeno {minLength} caratteri (ne sono stati inseriti {length}).',
10983	maxLength: 'Inserire al massimo {maxLength} caratteri (ne sono stati inseriti {length}).',
10984	integer: 'Inserire un numero intero. Non sono consentiti decimali (es.: 1.25).',
10985	numeric: 'Inserire solo valori numerici (es.: "1" oppure "1.1" oppure "-1" oppure "-1.1").',
10986	digits: 'Inserire solo numeri e caratteri di punteggiatura. Per esempio &egrave; consentito un numero telefonico con trattini o punti.',
10987	alpha: 'Inserire solo lettere (a-z). Non sono consentiti spazi o altri caratteri.',
10988	alphanum: 'Inserire solo lettere (a-z) o numeri (0-9). Non sono consentiti spazi o altri caratteri.',
10989	dateSuchAs: 'Inserire una data valida del tipo {date}',
10990	dateInFormatMDY: 'Inserire una data valida nel formato MM/GG/AAAA (es.: "12/31/1999")',
10991	email: 'Inserire un indirizzo email valido. Per esempio "[email protected]".',
10992	url: 'Inserire un indirizzo valido. Per esempio "http://www.example.com".',
10993	currencyDollar: 'Inserire un importo valido. Per esempio "$100.00".',
10994	oneRequired: 'Completare almeno uno dei campi richiesti.',
10995	errorPrefix: 'Errore: ',
10996	warningPrefix: 'Attenzione: ',
10997
10998	// Form.Validator.Extras
10999	noSpace: 'Non sono consentiti spazi.',
11000	reqChkByNode: 'Nessuna voce selezionata.',
11001	requiredChk: 'Il campo &egrave; obbligatorio.',
11002	reqChkByName: 'Selezionare un(a) {label}.',
11003	match: 'Il valore deve corrispondere al campo {matchName}',
11004	startDate: "data d'inizio",
11005	endDate: 'data di fine',
11006	currentDate: 'data attuale',
11007	afterDate: 'La data deve corrispondere o essere successiva al {label}.',
11008	beforeDate: 'La data deve corrispondere o essere precedente al {label}.',
11009	startMonth: "Selezionare un mese d'inizio",
11010	sameMonth: 'Le due date devono essere dello stesso mese - occorre modificarne una.'
11011
11012});
11013
11014/*
11015---
11016
11017name: Locale.ja-JP.Date
11018
11019description: Date messages for Japanese.
11020
11021license: MIT-style license
11022
11023authors:
11024  - Noritaka Horio
11025
11026requires:
11027  - Locale
11028
11029provides: [Locale.ja-JP.Date]
11030
11031...
11032*/
11033
11034Locale.define('ja-JP', 'Date', {
11035
11036	months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
11037	months_abbr: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
11038	days: ['日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日'],
11039	days_abbr: ['日', '月', '火', '水', '木', '金', '土'],
11040
11041	// Culture's date order: YYYY/MM/DD
11042	dateOrder: ['year', 'month', 'date'],
11043	shortDate: '%Y/%m/%d',
11044	shortTime: '%H:%M',
11045	AM: '午前',
11046	PM: '午後',
11047	firstDayOfWeek: 0,
11048
11049	// Date.Extras
11050	ordinal: '',
11051
11052	lessThanMinuteAgo: '1分以内前',
11053	minuteAgo: '約1分前',
11054	minutesAgo: '約{delta}分前',
11055	hourAgo: '約1時間前',
11056	hoursAgo: '約{delta}時間前',
11057	dayAgo: '1日前',
11058	daysAgo: '{delta}日前',
11059	weekAgo: '1週間前',
11060	weeksAgo: '{delta}週間前',
11061	monthAgo: '1ヶ月前',
11062	monthsAgo: '{delta}ヶ月前',
11063	yearAgo: '1年前',
11064	yearsAgo: '{delta}年前',
11065
11066	lessThanMinuteUntil: '今から約1分以内',
11067	minuteUntil: '今から約1分',
11068	minutesUntil: '今から約{delta}分',
11069	hourUntil: '今から約1時間',
11070	hoursUntil: '今から約{delta}時間',
11071	dayUntil: '今から1日間',
11072	daysUntil: '今から{delta}日間',
11073	weekUntil: '今から1週間',
11074	weeksUntil: '今から{delta}週間',
11075	monthUntil: '今から1ヶ月',
11076	monthsUntil: '今から{delta}ヶ月',
11077	yearUntil: '今から1年',
11078	yearsUntil: '今から{delta}年'
11079
11080});
11081
11082/*
11083---
11084
11085name: Locale.ja-JP.Form.Validator
11086
11087description: Form Validator messages for Japanese.
11088
11089license: MIT-style license
11090
11091authors:
11092  - Noritaka Horio
11093
11094requires:
11095  - Locale
11096
11097provides: [Locale.ja-JP.Form.Validator]
11098
11099...
11100*/
11101
11102Locale.define('ja-JP', 'FormValidator', {
11103
11104	required: '入力は必須です。',
11105	minLength: '入力文字数は{minLength}以上にしてください。({length}文字)',
11106	maxLength: '入力文字数は{maxLength}以下にしてください。({length}文字)',
11107	integer: '整数を入力してください。',
11108	numeric: '入力できるのは数値だけです。(例: "1", "1.1", "-1", "-1.1"....)',
11109	digits: '入力できるのは数値と句読記号です。 (例: -や+を含む電話番号など).',
11110	alpha: '入力できるのは半角英字だけです。それ以外の文字は入力できません。',
11111	alphanum: '入力できるのは半角英数字だけです。それ以外の文字は入力できません。',
11112	dateSuchAs: '有効な日付を入力してください。{date}',
11113	dateInFormatMDY: '日付の書式に誤りがあります。YYYY/MM/DD (i.e. "1999/12/31")',
11114	email: 'メールアドレスに誤りがあります。',
11115	url: 'URLアドレスに誤りがあります。',
11116	currencyDollar: '金額に誤りがあります。',
11117	oneRequired: 'ひとつ以上入力してください。',
11118	errorPrefix: 'エラー: ',
11119	warningPrefix: '警告: ',
11120
11121	// FormValidator.Extras
11122	noSpace: 'スペースは入力できません。',
11123	reqChkByNode: '選択されていません。',
11124	requiredChk: 'この項目は必須です。',
11125	reqChkByName: '{label}を選択してください。',
11126	match: '{matchName}が入力されている場合必須です。',
11127	startDate: '開始日',
11128	endDate: '終了日',
11129	currentDate: '今日',
11130	afterDate: '{label}以降の日付にしてください。',
11131	beforeDate: '{label}以前の日付にしてください。',
11132	startMonth: '開始月を選択してください。',
11133	sameMonth: '日付が同一です。どちらかを変更してください。'
11134
11135});
11136
11137/*
11138---
11139
11140name: Locale.ja-JP.Number
11141
11142description: Number messages for Japanese.
11143
11144license: MIT-style license
11145
11146authors:
11147  - Noritaka Horio
11148
11149requires:
11150  - Locale
11151
11152provides: [Locale.ja-JP.Number]
11153
11154...
11155*/
11156
11157Locale.define('ja-JP', 'Number', {
11158
11159	decimal: '.',
11160	group: ',',
11161
11162	currency: {
11163		decimals: 0,
11164		prefix: '\\'
11165	}
11166
11167});
11168
11169/*
11170---
11171
11172name: Locale.nl-NL.Date
11173
11174description: Date messages for Dutch.
11175
11176license: MIT-style license
11177
11178authors:
11179  - Lennart Pilon
11180  - Tim Wienk
11181
11182requires:
11183  - Locale
11184
11185provides: [Locale.nl-NL.Date]
11186
11187...
11188*/
11189
11190Locale.define('nl-NL', 'Date', {
11191
11192	months: ['januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december'],
11193	months_abbr: ['jan', 'feb', 'mrt', 'apr', 'mei', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'],
11194	days: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'],
11195	days_abbr: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'],
11196
11197	// Culture's date order: DD-MM-YYYY
11198	dateOrder: ['date', 'month', 'year'],
11199	shortDate: '%d-%m-%Y',
11200	shortTime: '%H:%M',
11201	AM: 'AM',
11202	PM: 'PM',
11203	firstDayOfWeek: 1,
11204
11205	// Date.Extras
11206	ordinal: 'e',
11207
11208	lessThanMinuteAgo: 'minder dan een minuut geleden',
11209	minuteAgo: 'ongeveer een minuut geleden',
11210	minutesAgo: '{delta} minuten geleden',
11211	hourAgo: 'ongeveer een uur geleden',
11212	hoursAgo: 'ongeveer {delta} uur geleden',
11213	dayAgo: 'een dag geleden',
11214	daysAgo: '{delta} dagen geleden',
11215	weekAgo: 'een week geleden',
11216	weeksAgo: '{delta} weken geleden',
11217	monthAgo: 'een maand geleden',
11218	monthsAgo: '{delta} maanden geleden',
11219	yearAgo: 'een jaar geleden',
11220	yearsAgo: '{delta} jaar geleden',
11221
11222	lessThanMinuteUntil: 'over minder dan een minuut',
11223	minuteUntil: 'over ongeveer een minuut',
11224	minutesUntil: 'over {delta} minuten',
11225	hourUntil: 'over ongeveer een uur',
11226	hoursUntil: 'over {delta} uur',
11227	dayUntil: 'over ongeveer een dag',
11228	daysUntil: 'over {delta} dagen',
11229	weekUntil: 'over een week',
11230	weeksUntil: 'over {delta} weken',
11231	monthUntil: 'over een maand',
11232	monthsUntil: 'over {delta} maanden',
11233	yearUntil: 'over een jaar',
11234	yearsUntil: 'over {delta} jaar'
11235
11236});
11237
11238/*
11239---
11240
11241name: Locale.nl-NL.Form.Validator
11242
11243description: Form Validator messages for Dutch.
11244
11245license: MIT-style license
11246
11247authors:
11248  - Lennart Pilon
11249  - Arian Stolwijk
11250  - Tim Wienk
11251
11252requires:
11253  - Locale
11254
11255provides: [Locale.nl-NL.Form.Validator]
11256
11257...
11258*/
11259
11260Locale.define('nl-NL', 'FormValidator', {
11261
11262	required: 'Dit veld is verplicht.',
11263	length: 'Vul precies {length} karakters in (je hebt {elLength} karakters ingevoerd).',
11264	minLength: 'Vul minimaal {minLength} karakters in (je hebt {length} karakters ingevoerd).',
11265	maxLength: 'Vul niet meer dan {maxLength} karakters in (je hebt {length} karakters ingevoerd).',
11266	integer: 'Vul een getal in. Getallen met decimalen (bijvoorbeeld 1.25) zijn niet toegestaan.',
11267	numeric: 'Vul alleen numerieke waarden in (bijvoorbeeld "1" of "1.1" of "-1" of "-1.1").',
11268	digits: 'Vul alleen nummers en leestekens in (bijvoorbeeld een telefoonnummer met streepjes is toegestaan).',
11269	alpha: 'Vul alleen letters in (a-z). Spaties en andere karakters zijn niet toegestaan.',
11270	alphanum: 'Vul alleen letters (a-z) of nummers (0-9) in. Spaties en andere karakters zijn niet toegestaan.',
11271	dateSuchAs: 'Vul een geldige datum in, zoals {date}',
11272	dateInFormatMDY: 'Vul een geldige datum, in het formaat MM/DD/YYYY (bijvoorbeeld "12/31/1999")',
11273	email: 'Vul een geldig e-mailadres in. Bijvoorbeeld "[email protected]".',
11274	url: 'Vul een geldige URL in, zoals http://www.example.com.',
11275	currencyDollar: 'Vul een geldig $ bedrag in. Bijvoorbeeld $100.00 .',
11276	oneRequired: 'Vul iets in bij in ieder geval een van deze velden.',
11277	warningPrefix: 'Waarschuwing: ',
11278	errorPrefix: 'Fout: ',
11279
11280	// Form.Validator.Extras
11281	noSpace: 'Spaties zijn niet toegestaan in dit veld.',
11282	reqChkByNode: 'Er zijn geen items geselecteerd.',
11283	requiredChk: 'Dit veld is verplicht.',
11284	reqChkByName: 'Selecteer een {label}.',
11285	match: 'Dit veld moet overeen komen met het {matchName} veld',
11286	startDate: 'de begin datum',
11287	endDate: 'de eind datum',
11288	currentDate: 'de huidige datum',
11289	afterDate: 'De datum moet hetzelfde of na {label} zijn.',
11290	beforeDate: 'De datum moet hetzelfde of voor {label} zijn.',
11291	startMonth: 'Selecteer een begin maand',
11292	sameMonth: 'Deze twee data moeten in dezelfde maand zijn - u moet een van beide aanpassen.',
11293	creditcard: 'Het ingevulde creditcardnummer is niet geldig. Controleer het nummer en probeer opnieuw. {length} getallen ingevuld.'
11294
11295});
11296
11297/*
11298---
11299
11300name: Locale.nl-NL.Number
11301
11302description: Number messages for Dutch.
11303
11304license: MIT-style license
11305
11306authors:
11307  - Arian Stolwijk
11308
11309requires:
11310  - Locale
11311  - Locale.EU.Number
11312
11313provides: [Locale.nl-NL.Number]
11314
11315...
11316*/
11317
11318Locale.define('nl-NL').inherit('EU', 'Number');
11319
11320
11321
11322
11323/*
11324---
11325
11326name: Locale.no-NO.Date
11327
11328description: Date messages for Norwegian.
11329
11330license: MIT-style license
11331
11332authors:
11333  - Espen 'Rexxars' Hovlandsdal
11334  - Ole Tøsse Kolvik
11335requires:
11336  - Locale
11337
11338provides: [Locale.no-NO.Date]
11339
11340...
11341*/
11342
11343Locale.define('no-NO', 'Date', {
11344	months: ['Januar', 'Februar', 'Mars', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Desember'],
11345	months_abbr: ['Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Des'],
11346	days: ['Søndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lørdag'],
11347	days_abbr: ['Søn', 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'Lør'],
11348
11349	// Culture's date order: DD.MM.YYYY
11350	dateOrder: ['date', 'month', 'year'],
11351	shortDate: '%d.%m.%Y',
11352	shortTime: '%H:%M',
11353	AM: 'AM',
11354	PM: 'PM',
11355	firstDayOfWeek: 1,
11356
11357	lessThanMinuteAgo: 'mindre enn et minutt siden',
11358	minuteAgo: 'omtrent et minutt siden',
11359	minutesAgo: '{delta} minutter siden',
11360	hourAgo: 'omtrent en time siden',
11361	hoursAgo: 'omtrent {delta} timer siden',
11362	dayAgo: '{delta} dag siden',
11363	daysAgo: '{delta} dager siden',
11364	weekAgo: 'en uke siden',
11365	weeksAgo: '{delta} uker siden',
11366	monthAgo: 'en måned siden',
11367	monthsAgo: '{delta} måneder siden',
11368	yearAgo: 'ett år siden',
11369	yearsAgo: '{delta} år siden',
11370
11371	lessThanMinuteUntil: 'mindre enn et minutt til',
11372	minuteUntil: 'omtrent et minutt til',
11373	minutesUntil: '{delta} minutter til',
11374	hourUntil: 'omtrent en time til',
11375	hoursUntil: 'omtrent {delta} timer til',
11376	dayUntil: 'en dag til',
11377	daysUntil: '{delta} dager til',
11378	weekUntil: 'en uke til',
11379	weeksUntil: '{delta} uker til',
11380	monthUntil: 'en måned til',
11381	monthsUntil: '{delta} måneder til',
11382	yearUntil: 'et år til',
11383	yearsUntil: '{delta} år til'
11384});
11385
11386/*
11387---
11388
11389name: Locale.no-NO.Form.Validator
11390
11391description: Form Validator messages for Norwegian.
11392
11393license: MIT-style license
11394
11395authors:
11396  - Aaron Newton
11397  - Espen 'Rexxars' Hovlandsdal
11398  - Ole Tøsse Kolvik
11399
11400requires:
11401  - Locale
11402
11403provides: [Locale.no-NO.Form.Validator]
11404
11405...
11406*/
11407
11408Locale.define('no-NO', 'FormValidator', {
11409
11410	required: 'Dette feltet er påkrevd.',
11411	length: 'Skriv inn {length} tegn (du skrev {elLength} tegn)',
11412	minLength: 'Skriv inn minst {minLength} tegn (du skrev {length} tegn).',
11413	maxLength: 'Ikke skriv mer enn {maxLength} tegn (du skrev {length} tegn).',
11414	integer: 'Skriv inn et tall i dette feltet. Tall med desimaler (f.eks. 1,25) er ikke tillat.',
11415	numeric: 'Skriv kun inn numeriske verdier i dette feltet (f.eks. "1", "1.1", "-1" eller "-1.1").',
11416	digits: 'Skriv kun nummer og skilletegn i dette feltet.',
11417	alpha: 'Skriv kun bokstaver (a-Ã¥) i dette feltet. Ingen mellomrom eller andre tegn er tillat.',
11418	alphanum: 'Skriv kun bokstaver (a-Ã¥) eller nummer (0-9) i dette feltet. Ingen mellomrom eller andre tegn er tillat.',
11419	dateSuchAs: 'Skriv inn en gyldig dato, som f.eks. {date}',
11420	dateInFormatMDY: 'Skriv inn en gyldig dato, f.eks. DD/MM/YYYY ("31/12/1999")',
11421	email: 'Skriv inn en gyldig epost-adresse. F.eks. "[email protected]".',
11422	url: 'Skriv inn en gyldig URL, f.eks. http://www.example.com.',
11423	currencyDollar: 'Skriv inn et gyldig beløp. F.eks. 100,00.',
11424	oneRequired: 'Minst ett av disse feltene må fylles ut.',
11425	errorPrefix: 'Feil: ',
11426	warningPrefix: 'Advarsel: ',
11427
11428	// Form.Validator.Extras
11429	noSpace: 'Mellomrom er ikke tillatt i dette feltet.',
11430	reqChkByNode: 'Ingen objekter er valgt.',
11431	requiredChk: 'Dette feltet er påkrevd.',
11432	reqChkByName: 'Velg en {label}.',
11433	match: 'Dette feltet må være lik {matchName}',
11434	startDate: 'startdato',
11435	endDate: 'sluttdato',
11436	currentDate: 'dagens dato',
11437	afterDate: 'Datoen må være den samme som eller etter {label}.',
11438	beforeDate: 'Datoen må være den samme som eller før {label}.',
11439	startMonth: 'Velg en startmåned',
11440	sameMonth: 'Datoene må være i den samme måneden - velg den ene eller den andre.',
11441	creditcard: 'Kortnummeret du skrev inn er ikke gyldig. Prøv igjen. Du skrev {length} siffer.'
11442
11443});
11444
11445/*
11446---
11447
11448name: Locale.no-NO.Number
11449
11450description: Number messages for Norwegian.
11451
11452license: MIT-style license
11453
11454authors:
11455  - Arian Stolwijk
11456  - Martin Lundgren
11457  - Ole T�sse Kolvik
11458
11459requires:
11460  - Locale
11461  - Locale.EU.Number
11462
11463provides: [Locale.no-NO.Number]
11464
11465...
11466*/
11467
11468Locale.define('no-NO', 'Number', {
11469
11470	currency: {
11471		prefix: 'NOK '
11472	}
11473
11474}).inherit('EU', 'Number');
11475
11476/*
11477---
11478
11479name: Locale.pl-PL.Date
11480
11481description: Date messages for Polish.
11482
11483license: MIT-style license
11484
11485authors:
11486  - Oskar Krawczyk
11487
11488requires:
11489  - Locale
11490
11491provides: [Locale.pl-PL.Date]
11492
11493...
11494*/
11495
11496Locale.define('pl-PL', 'Date', {
11497
11498	months: ['Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', 'Czerwiec', 'Lipiec', 'Sierpień', 'Wrzesień', 'Październik', 'Listopad', 'Grudzień'],
11499	months_abbr: ['sty', 'lut', 'mar', 'kwi', 'maj', 'cze', 'lip', 'sie', 'wrz', 'paź', 'lis', 'gru'],
11500	days: ['Niedziela', 'Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota'],
11501	days_abbr: ['niedz.', 'pon.', 'wt.', 'śr.', 'czw.', 'pt.', 'sob.'],
11502
11503	// Culture's date order: YYYY-MM-DD
11504	dateOrder: ['year', 'month', 'date'],
11505	shortDate: '%Y-%m-%d',
11506	shortTime: '%H:%M',
11507	AM: 'nad ranem',
11508	PM: 'po południu',
11509	firstDayOfWeek: 1,
11510
11511	// Date.Extras
11512	ordinal: function(dayOfMonth){
11513		return (dayOfMonth > 3 && dayOfMonth < 21) ? 'ty' : ['ty', 'szy', 'gi', 'ci', 'ty'][Math.min(dayOfMonth % 10, 4)];
11514	},
11515
11516	lessThanMinuteAgo: 'mniej niż minute temu',
11517	minuteAgo: 'około minutę temu',
11518	minutesAgo: '{delta} minut temu',
11519	hourAgo: 'około godzinę temu',
11520	hoursAgo: 'około {delta} godzin temu',
11521	dayAgo: 'Wczoraj',
11522	daysAgo: '{delta} dni temu',
11523
11524	lessThanMinuteUntil: 'za niecałą minutę',
11525	minuteUntil: 'za około minutę',
11526	minutesUntil: 'za {delta} minut',
11527	hourUntil: 'za około godzinę',
11528	hoursUntil: 'za około {delta} godzin',
11529	dayUntil: 'za 1 dzień',
11530	daysUntil: 'za {delta} dni'
11531
11532});
11533
11534/*
11535---
11536
11537name: Locale.pl-PL.Form.Validator
11538
11539description: Form Validator messages for Polish.
11540
11541license: MIT-style license
11542
11543authors:
11544  - Oskar Krawczyk
11545
11546requires:
11547  - Locale
11548
11549provides: [Locale.pl-PL.Form.Validator]
11550
11551...
11552*/
11553
11554Locale.define('pl-PL', 'FormValidator', {
11555
11556	required: 'To pole jest wymagane.',
11557	minLength: 'Wymagane jest przynajmniej {minLength} znaków (wpisanych zostało tylko {length}).',
11558	maxLength: 'Dozwolone jest nie więcej niż {maxLength} znaków (wpisanych zostało {length})',
11559	integer: 'To pole wymaga liczb całych. Liczby dziesiętne (np. 1.25) są niedozwolone.',
11560	numeric: 'Prosimy używać tylko numerycznych wartości w tym polu (np. "1", "1.1", "-1" lub "-1.1").',
11561	digits: 'Prosimy używać liczb oraz zankow punktuacyjnych w typ polu (dla przykładu, przy numerze telefonu myślniki i kropki są dozwolone).',
11562	alpha: 'Prosimy używać tylko liter (a-z) w tym polu. Spacje oraz inne znaki są niedozwolone.',
11563	alphanum: 'Prosimy używać tylko liter (a-z) lub liczb (0-9) w tym polu. Spacje oraz inne znaki są niedozwolone.',
11564	dateSuchAs: 'Prosimy podać prawidłową datę w formacie: {date}',
11565	dateInFormatMDY: 'Prosimy podać poprawną date w formacie DD.MM.RRRR (i.e. "12.01.2009")',
11566	email: 'Prosimy podać prawidłowy adres e-mail, np. "[email protected]".',
11567	url: 'Prosimy podać prawidłowy adres URL, np. http://www.example.com.',
11568	currencyDollar: 'Prosimy podać prawidłową sumę w PLN. Dla przykładu: 100.00 PLN.',
11569	oneRequired: 'Prosimy wypełnić chociaż jedno z pól.',
11570	errorPrefix: 'Błąd: ',
11571	warningPrefix: 'Uwaga: ',
11572
11573	// Form.Validator.Extras
11574	noSpace: 'W tym polu nie mogą znajdować się spacje.',
11575	reqChkByNode: 'Brak zaznaczonych elementów.',
11576	requiredChk: 'To pole jest wymagane.',
11577	reqChkByName: 'Prosimy wybrać z {label}.',
11578	match: 'To pole musi być takie samo jak {matchName}',
11579	startDate: 'data początkowa',
11580	endDate: 'data końcowa',
11581	currentDate: 'aktualna data',
11582	afterDate: 'Podana data poinna być taka sama lub po {label}.',
11583	beforeDate: 'Podana data poinna być taka sama lub przed {label}.',
11584	startMonth: 'Prosimy wybrać początkowy miesiąc.',
11585	sameMonth: 'Te dwie daty muszą być w zakresie tego samego miesiąca - wymagana jest zmiana któregoś z pól.'
11586
11587});
11588
11589/*
11590---
11591
11592name: Locale.pt-PT.Date
11593
11594description: Date messages for Portuguese.
11595
11596license: MIT-style license
11597
11598authors:
11599  - Fabio Miranda Costa
11600
11601requires:
11602  - Locale
11603
11604provides: [Locale.pt-PT.Date]
11605
11606...
11607*/
11608
11609Locale.define('pt-PT', 'Date', {
11610
11611	months: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'],
11612	months_abbr: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'],
11613	days: ['Domingo', 'Segunda-feira', 'Terça-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', 'Sábado'],
11614	days_abbr: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'],
11615
11616	// Culture's date order: DD-MM-YYYY
11617	dateOrder: ['date', 'month', 'year'],
11618	shortDate: '%d-%m-%Y',
11619	shortTime: '%H:%M',
11620	AM: 'AM',
11621	PM: 'PM',
11622	firstDayOfWeek: 1,
11623
11624	// Date.Extras
11625	ordinal: 'º',
11626
11627	lessThanMinuteAgo: 'há menos de um minuto',
11628	minuteAgo: 'há cerca de um minuto',
11629	minutesAgo: 'há {delta} minutos',
11630	hourAgo: 'há cerca de uma hora',
11631	hoursAgo: 'há cerca de {delta} horas',
11632	dayAgo: 'há um dia',
11633	daysAgo: 'há {delta} dias',
11634	weekAgo: 'há uma semana',
11635	weeksAgo: 'há {delta} semanas',
11636	monthAgo: 'há um mês',
11637	monthsAgo: 'há {delta} meses',
11638	yearAgo: 'há um ano',
11639	yearsAgo: 'há {delta} anos',
11640
11641	lessThanMinuteUntil: 'em menos de um minuto',
11642	minuteUntil: 'em um minuto',
11643	minutesUntil: 'em {delta} minutos',
11644	hourUntil: 'em uma hora',
11645	hoursUntil: 'em {delta} horas',
11646	dayUntil: 'em um dia',
11647	daysUntil: 'em {delta} dias',
11648	weekUntil: 'em uma semana',
11649	weeksUntil: 'em {delta} semanas',
11650	monthUntil: 'em um mês',
11651	monthsUntil: 'em {delta} meses',
11652	yearUntil: 'em um ano',
11653	yearsUntil: 'em {delta} anos'
11654
11655});
11656
11657/*
11658---
11659
11660name: Locale.pt-BR.Date
11661
11662description: Date messages for Portuguese (Brazil).
11663
11664license: MIT-style license
11665
11666authors:
11667  - Fabio Miranda Costa
11668
11669requires:
11670  - Locale
11671  - Locale.pt-PT.Date
11672
11673provides: [Locale.pt-BR.Date]
11674
11675...
11676*/
11677
11678Locale.define('pt-BR', 'Date', {
11679
11680	// Culture's date order: DD/MM/YYYY
11681	shortDate: '%d/%m/%Y'
11682
11683}).inherit('pt-PT', 'Date');
11684
11685/*
11686---
11687
11688name: Locale.pt-BR.Form.Validator
11689
11690description: Form Validator messages for Portuguese (Brazil).
11691
11692license: MIT-style license
11693
11694authors:
11695  - Fábio Miranda Costa
11696
11697requires:
11698  - Locale
11699
11700provides: [Locale.pt-BR.Form.Validator]
11701
11702...
11703*/
11704
11705Locale.define('pt-BR', 'FormValidator', {
11706
11707	required: 'Este campo é obrigatório.',
11708	minLength: 'Digite pelo menos {minLength} caracteres (tamanho atual: {length}).',
11709	maxLength: 'Não digite mais de {maxLength} caracteres (tamanho atual: {length}).',
11710	integer: 'Por favor digite apenas um número inteiro neste campo. Não são permitidos números decimais (por exemplo, 1,25).',
11711	numeric: 'Por favor digite apenas valores numéricos neste campo (por exemplo, "1" ou "1.1" ou "-1" ou "-1,1").',
11712	digits: 'Por favor use apenas números e pontuação neste campo (por exemplo, um número de telefone com traços ou pontos é permitido).',
11713	alpha: 'Por favor use somente letras (a-z). Espaço e outros caracteres não são permitidos.',
11714	alphanum: 'Use somente letras (a-z) ou números (0-9) neste campo. Espaço e outros caracteres não são permitidos.',
11715	dateSuchAs: 'Digite uma data válida, como {date}',
11716	dateInFormatMDY: 'Digite uma data válida, como DD/MM/YYYY (por exemplo, "31/12/1999")',
11717	email: 'Digite um endereço de email válido. Por exemplo "[email protected]".',
11718	url: 'Digite uma URL válida. Exemplo: http://www.example.com.',
11719	currencyDollar: 'Digite um valor em dinheiro válido. Exemplo: R$100,00 .',
11720	oneRequired: 'Digite algo para pelo menos um desses campos.',
11721	errorPrefix: 'Erro: ',
11722	warningPrefix: 'Aviso: ',
11723
11724	// Form.Validator.Extras
11725	noSpace: 'Não é possível digitar espaços neste campo.',
11726	reqChkByNode: 'Não foi selecionado nenhum item.',
11727	requiredChk: 'Este campo é obrigatório.',
11728	reqChkByName: 'Por favor digite um {label}.',
11729	match: 'Este campo deve ser igual ao campo {matchName}.',
11730	startDate: 'a data inicial',
11731	endDate: 'a data final',
11732	currentDate: 'a data atual',
11733	afterDate: 'A data deve ser igual ou posterior a {label}.',
11734	beforeDate: 'A data deve ser igual ou anterior a {label}.',
11735	startMonth: 'Por favor selecione uma data inicial.',
11736	sameMonth: 'Estas duas datas devem ter o mesmo mês - você deve modificar uma das duas.',
11737	creditcard: 'O número do cartão de crédito informado é inválido. Por favor verifique o valor e tente novamente. {length} números informados.'
11738
11739});
11740
11741/*
11742---
11743
11744name: Locale.pt-BR.Number
11745
11746description: Number messages for PT Brazilian.
11747
11748license: MIT-style license
11749
11750authors:
11751  - Arian Stolwijk
11752  - Danillo César
11753
11754requires:
11755  - Locale
11756
11757provides: [Locale.pt-BR.Number]
11758
11759...
11760*/
11761
11762Locale.define('pt-BR', 'Number', {
11763
11764	decimal: ',',
11765	group: '.',
11766
11767	currency: {
11768		prefix: 'R$ '
11769	}
11770
11771});
11772
11773
11774
11775/*
11776---
11777
11778name: Locale.pt-PT.Form.Validator
11779
11780description: Form Validator messages for Portuguese.
11781
11782license: MIT-style license
11783
11784authors:
11785  - Miquel Hudin
11786
11787requires:
11788  - Locale
11789
11790provides: [Locale.pt-PT.Form.Validator]
11791
11792...
11793*/
11794
11795Locale.define('pt-PT', 'FormValidator', {
11796
11797	required: 'Este campo é necessário.',
11798	minLength: 'Digite pelo menos{minLength} caracteres (comprimento {length} caracteres).',
11799	maxLength: 'Não insira mais de {maxLength} caracteres (comprimento {length} caracteres).',
11800	integer: 'Digite um número inteiro neste domínio. Com números decimais (por exemplo, 1,25), não são permitidas.',
11801	numeric: 'Digite apenas valores numéricos neste domínio (p.ex., "1" ou "1.1" ou "-1" ou "-1,1").',
11802	digits: 'Por favor, use números e pontuação apenas neste campo (p.ex., um número de telefone com traços ou pontos é permitida).',
11803	alpha: 'Por favor use somente letras (a-z), com nesta área. Não utilize espaços nem outros caracteres são permitidos.',
11804	alphanum: 'Use somente letras (a-z) ou números (0-9) neste campo. Não utilize espaços nem outros caracteres são permitidos.',
11805	dateSuchAs: 'Digite uma data válida, como {date}',
11806	dateInFormatMDY: 'Digite uma data válida, como DD/MM/YYYY (p.ex. "31/12/1999")',
11807	email: 'Digite um endereço de email válido. Por exemplo "[email protected]".',
11808	url: 'Digite uma URL válida, como http://www.example.com.',
11809	currencyDollar: 'Digite um valor válido $. Por exemplo $ 100,00. ',
11810	oneRequired: 'Digite algo para pelo menos um desses insumos.',
11811	errorPrefix: 'Erro: ',
11812	warningPrefix: 'Aviso: '
11813
11814});
11815
11816/*
11817---
11818
11819name: Locale.ru-RU-unicode.Date
11820
11821description: Date messages for Russian (utf-8).
11822
11823license: MIT-style license
11824
11825authors:
11826  - Evstigneev Pavel
11827  - Kuryanovich Egor
11828
11829requires:
11830  - Locale
11831
11832provides: [Locale.ru-RU.Date]
11833
11834...
11835*/
11836
11837(function(){
11838
11839// Russian language pluralization rules, taken from CLDR project, http://unicode.org/cldr/
11840// one -> n mod 10 is 1 and n mod 100 is not 11;
11841// few -> n mod 10 in 2..4 and n mod 100 not in 12..14;
11842// many -> n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14;
11843// other -> everything else (example 3.14)
11844var pluralize = function(n, one, few, many, other){
11845	var modulo10 = n % 10,
11846		modulo100 = n % 100;
11847
11848	if (modulo10 == 1 && modulo100 != 11){
11849		return one;
11850	} else if ((modulo10 == 2 || modulo10 == 3 || modulo10 == 4) && !(modulo100 == 12 || modulo100 == 13 || modulo100 == 14)){
11851		return few;
11852	} else if (modulo10 == 0 || (modulo10 == 5 || modulo10 == 6 || modulo10 == 7 || modulo10 == 8 || modulo10 == 9) || (modulo100 == 11 || modulo100 == 12 || modulo100 == 13 || modulo100 == 14)){
11853		return many;
11854	} else {
11855		return other;
11856	}
11857};
11858
11859Locale.define('ru-RU', 'Date', {
11860
11861	months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],
11862	months_abbr: ['янв', 'февр', 'март', 'апр', 'май','июнь','июль','авг','сент','окт','нояб','дек'],
11863	days: ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'],
11864	days_abbr: ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'],
11865
11866	// Culture's date order: DD.MM.YYYY
11867	dateOrder: ['date', 'month', 'year'],
11868	shortDate: '%d.%m.%Y',
11869	shortTime: '%H:%M',
11870	AM: 'AM',
11871	PM: 'PM',
11872	firstDayOfWeek: 1,
11873
11874	// Date.Extras
11875	ordinal: '',
11876
11877	lessThanMinuteAgo: 'меньше минуты назад',
11878	minuteAgo: 'минуту назад',
11879	minutesAgo: function(delta){ return '{delta} ' + pluralize(delta, 'минуту', 'минуты', 'минут') + ' назад'; },
11880	hourAgo: 'час назад',
11881	hoursAgo: function(delta){ return '{delta} ' + pluralize(delta, 'час', 'часа', 'часов') + ' назад'; },
11882	dayAgo: 'вчера',
11883	daysAgo: function(delta){ return '{delta} ' + pluralize(delta, 'день', 'дня', 'дней') + ' назад'; },
11884	weekAgo: 'неделю назад',
11885	weeksAgo: function(delta){ return '{delta} ' + pluralize(delta, 'неделя', 'недели', 'недель') + ' назад'; },
11886	monthAgo: 'месяц назад',
11887	monthsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'месяц', 'месяца', 'месяцев') + ' назад'; },
11888	yearAgo: 'год назад',
11889	yearsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'год', 'года', 'лет') + ' назад'; },
11890
11891	lessThanMinuteUntil: 'меньше чем через минуту',
11892	minuteUntil: 'через минуту',
11893	minutesUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'минуту', 'минуты', 'минут') + ''; },
11894	hourUntil: 'через час',
11895	hoursUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'час', 'часа', 'часов') + ''; },
11896	dayUntil: 'завтра',
11897	daysUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'день', 'дня', 'дней') + ''; },
11898	weekUntil: 'через неделю',
11899	weeksUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'неделю', 'недели', 'недель') + ''; },
11900	monthUntil: 'через месяц',
11901	monthsUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'месяц', 'месяца', 'месяцев') + ''; },
11902	yearUntil: 'через',
11903	yearsUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'год', 'года', 'лет') + ''; }
11904
11905});
11906
11907
11908
11909})();
11910
11911/*
11912---
11913
11914name: Locale.ru-RU-unicode.Form.Validator
11915
11916description: Form Validator messages for Russian (utf-8).
11917
11918license: MIT-style license
11919
11920authors:
11921  - Chernodarov Egor
11922
11923requires:
11924  - Locale
11925
11926provides: [Locale.ru-RU.Form.Validator]
11927
11928...
11929*/
11930
11931Locale.define('ru-RU', 'FormValidator', {
11932
11933	required: 'Это поле обязательно к заполнению.',
11934	minLength: 'Пожалуйста, введите хотя бы {minLength} символов (Вы ввели {length}).',
11935	maxLength: 'Пожалуйста, введите не больше {maxLength} символов (Вы ввели {length}).',
11936	integer: 'Пожалуйста, введите в это поле число. Дробные числа (например 1.25) тут не разрешены.',
11937	numeric: 'Пожалуйста, введите в это поле число (например "1" или "1.1", или "-1", или "-1.1").',
11938	digits: 'В этом поле Вы можете использовать только цифры и знаки пунктуации (например, телефонный номер со знаками дефиса или с точками).',
11939	alpha: 'В этом поле можно использовать только латинские буквы (a-z). Пробелы и другие символы запрещены.',
11940	alphanum: 'В этом поле можно использовать только латинские буквы (a-z) и цифры (0-9). Пробелы и другие символы запрещены.',
11941	dateSuchAs: 'Пожалуйста, введите корректную дату {date}',
11942	dateInFormatMDY: 'Пожалуйста, введите дату в формате ММ/ДД/ГГГГ (например "12/31/1999")',
11943	email: 'Пожалуйста, введите корректный емейл-адрес. Для примера "[email protected]".',
11944	url: 'Пожалуйста, введите правильную ссылку вида http://www.example.com.',
11945	currencyDollar: 'Пожалуйста, введите сумму в долларах. Например: $100.00 .',
11946	oneRequired: 'Пожалуйста, выберите хоть что-нибудь в одном из этих полей.',
11947	errorPrefix: 'Ошибка: ',
11948	warningPrefix: 'Внимание: '
11949
11950});
11951
11952
11953
11954/*
11955---
11956
11957name: Locale.sk-SK.Date
11958
11959description: Date messages for Slovak.
11960
11961license: MIT-style license
11962
11963authors:
11964  - Ivan Masár
11965
11966requires:
11967  - Locale
11968
11969provides: [Locale.sk-SK.Date]
11970
11971...
11972*/
11973(function(){
11974
11975// Slovak language pluralization rules, see http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
11976// one -> n is 1;            1
11977// few -> n in 2..4;         2-4
11978// other -> everything else  0, 5-999, 1.31, 2.31, 5.31...
11979var pluralize = function(n, one, few, other){
11980	if (n == 1) return one;
11981	else if (n == 2 || n == 3 || n == 4) return few;
11982	else return other;
11983};
11984
11985Locale.define('sk-SK', 'Date', {
11986
11987	months: ['Január', 'Február', 'Marec', 'Apríl', 'Máj', 'Jún', 'Júl', 'August', 'September', 'Október', 'November', 'December'],
11988	months_abbr: ['januára', 'februára', 'marca', 'apríla', 'mája', 'júna', 'júla', 'augusta', 'septembra', 'októbra', 'novembra', 'decembra'],
11989	days: ['Nedele', 'Pondelí', 'Úterý', 'Streda', 'Čtvrtek', 'Pátek', 'Sobota'],
11990	days_abbr: ['ne', 'po', 'ut', 'st', 'št', 'pi', 'so'],
11991
11992	// Culture's date order: DD.MM.YYYY
11993	dateOrder: ['date', 'month', 'year'],
11994	shortDate: '%d.%m.%Y',
11995	shortTime: '%H:%M',
11996	AM: 'dop.',
11997	PM: 'pop.',
11998	firstDayOfWeek: 1,
11999
12000	// Date.Extras
12001	ordinal: '.',
12002
12003	lessThanMinuteAgo: 'pred chvíľou',
12004	minuteAgo: 'približne pred minútou',
12005	minutesAgo: function(delta){ return 'pred {delta} ' + pluralize(delta, 'minútou', 'minútami', 'minútami'); },
12006	hourAgo: 'približne pred hodinou',
12007	hoursAgo: function(delta){ return 'pred {delta} ' + pluralize(delta, 'hodinou', 'hodinami', 'hodinami'); },
12008	dayAgo: 'pred dňom',
12009	daysAgo: function(delta){ return 'pred {delta} ' + pluralize(delta, 'dňom', 'dňami', 'dňami'); },
12010	weekAgo: 'pred týždňom',
12011	weeksAgo: function(delta){ return 'pred {delta} ' + pluralize(delta, 'týždňom', 'týždňami', 'týždňami'); },
12012	monthAgo: 'pred mesiacom',
12013	monthsAgo: function(delta){ return 'pred {delta} ' + pluralize(delta, 'mesiacom', 'mesiacmi', 'mesiacmi'); },
12014	yearAgo: 'pred rokom',
12015	yearsAgo: function(delta){ return 'pred {delta} ' + pluralize(delta, 'rokom', 'rokmi', 'rokmi'); },
12016
12017	lessThanMinuteUntil: 'o chvíľu',
12018	minuteUntil: 'približne o minútu',
12019	minutesUntil: function(delta){ return 'o {delta} ' + pluralize(delta, 'minútu', 'minúty', 'minúty'); },
12020	hourUntil: 'približne o hodinu',
12021	hoursUntil: function(delta){ return 'o {delta} ' + pluralize(delta, 'hodinu', 'hodiny', 'hodín'); },
12022	dayUntil: 'o deň',
12023	daysUntil: function(delta){ return 'o {delta} ' + pluralize(delta, 'deň', 'dni', 'dní'); },
12024	weekUntil: 'o týždeň',
12025	weeksUntil: function(delta){ return 'o {delta} ' + pluralize(delta, 'týždeň', 'týždne', 'týždňov'); },
12026	monthUntil: 'o mesiac',
12027	monthsUntil: function(delta){ return 'o {delta} ' + pluralize(delta, 'mesiac', 'mesiace', 'mesiacov'); },
12028	yearUntil: 'o rok',
12029	yearsUntil: function(delta){ return 'o {delta} ' + pluralize(delta, 'rok', 'roky', 'rokov'); }
12030});
12031
12032})();
12033
12034/*
12035---
12036
12037name: Locale.sk-SK.Form.Validator
12038
12039description: Form Validator messages for Czech.
12040
12041license: MIT-style license
12042
12043authors:
12044  - Ivan Masár
12045
12046requires:
12047  - Locale
12048
12049provides: [Locale.sk-SK.Form.Validator]
12050
12051...
12052*/
12053
12054Locale.define('sk-SK', 'FormValidator', {
12055
12056	required: 'Táto položka je povinná.',
12057	minLength: 'Zadajte prosím aspoň {minLength} znakov (momentálne {length} znakov).',
12058	maxLength: 'Zadajte prosím menej ako {maxLength} znakov (momentálne {length} znakov).',
12059	integer: 'Zadajte prosím celé číslo. Desetinné čísla (napr. 1.25) nie sú povolené.',
12060	numeric: 'Zadajte len číselné hodnoty (t.j. „1“ alebo „1.1“ alebo „-1“ alebo „-1.1“).',
12061	digits: 'Zadajte prosím len čísla a interpunkčné znamienka (napríklad telefónne číslo s pomlčkami albo bodkami je povolené).',
12062	alpha: 'Zadajte prosím len písmená (a-z). Medzery alebo iné znaky nie sú povolené.',
12063	alphanum: 'Zadajte prosím len písmená (a-z) alebo číslice (0-9). Medzery alebo iné znaky nie sú povolené.',
12064	dateSuchAs: 'Zadajte prosím platný dátum v tvare {date}',
12065	dateInFormatMDY: 'Zadajte prosím platný datum v tvare MM / DD / RRRR (t.j. „12/31/1999“)',
12066	email: 'Zadajte prosím platnú emailovú adresu. Napríklad „[email protected]“.',
12067	url: 'Zadajte prosím platnoú adresu URL v tvare http://www.example.com.',
12068	currencyDollar: 'Zadajte prosím platnú čiastku. Napríklad $100.00.',
12069	oneRequired: 'Zadajte prosím aspoň jednu hodnotu z týchto položiek.',
12070	errorPrefix: 'Chyba: ',
12071	warningPrefix: 'Upozornenie: ',
12072
12073	// Form.Validator.Extras
12074	noSpace: 'V tejto položle nie sú povolené medzery',
12075	reqChkByNode: 'Nie sú vybrané žiadne položky.',
12076	requiredChk: 'Táto položka je povinná.',
12077	reqChkByName: 'Prosím vyberte {label}.',
12078	match: 'Táto položka sa musí zhodovať s položkou {matchName}',
12079	startDate: 'dátum začiatku',
12080	endDate: 'dátum ukončenia',
12081	currendDate: 'aktuálny dátum',
12082	afterDate: 'Dátum by mal býť rovnaký alebo väčší ako {label}.',
12083	beforeDate: 'Dátum by mal byť rovnaký alebo menší ako {label}.',
12084	startMonth: 'Vyberte počiatočný mesiac.',
12085	sameMonth: 'Tieto dva dátumy musia býť v rovnakom mesiaci - zmeňte jeden z nich.',
12086	creditcard: 'Zadané číslo kreditnej karty je neplatné. Prosím, opravte ho. Bolo zadaných {length} číslic.'
12087
12088});
12089
12090/*
12091---
12092
12093name: Locale.si-SI.Date
12094
12095description: Date messages for Slovenian.
12096
12097license: MIT-style license
12098
12099authors:
12100  - Radovan Lozej
12101
12102requires:
12103  - Locale
12104
12105provides: [Locale.si-SI.Date]
12106
12107...
12108*/
12109
12110(function(){
12111
12112var pluralize = function(n, one, two, three, other){
12113	return (n >= 1 && n <= 3) ? arguments[n] : other;
12114};
12115
12116Locale.define('sl-SI', 'Date', {
12117
12118	months: ['januar', 'februar', 'marec', 'april', 'maj', 'junij', 'julij', 'avgust', 'september', 'oktober', 'november', 'december'],
12119	months_abbr: ['jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'avg', 'sep', 'okt', 'nov', 'dec'],
12120	days: ['nedelja', 'ponedeljek', 'torek', 'sreda', 'četrtek', 'petek', 'sobota'],
12121	days_abbr: ['ned', 'pon', 'tor', 'sre', 'čet', 'pet', 'sob'],
12122
12123	// Culture's date order: DD.MM.YYYY
12124	dateOrder: ['date', 'month', 'year'],
12125	shortDate: '%d.%m.%Y',
12126	shortTime: '%H.%M',
12127	AM: 'AM',
12128	PM: 'PM',
12129	firstDayOfWeek: 1,
12130
12131	// Date.Extras
12132	ordinal: '.',
12133
12134	lessThanMinuteAgo: 'manj kot minuto nazaj',
12135	minuteAgo: 'minuto nazaj',
12136	minutesAgo: function(delta){ return '{delta} ' + pluralize(delta, 'minuto', 'minuti', 'minute', 'minut') + ' nazaj'; },
12137	hourAgo: 'uro nazaj',
12138	hoursAgo: function(delta){ return '{delta} ' + pluralize(delta, 'uro', 'uri', 'ure', 'ur') + ' nazaj'; },
12139	dayAgo: 'dan nazaj',
12140	daysAgo: function(delta){ return '{delta} ' + pluralize(delta, 'dan', 'dneva', 'dni', 'dni') + ' nazaj'; },
12141	weekAgo: 'teden nazaj',
12142	weeksAgo: function(delta){ return '{delta} ' + pluralize(delta, 'teden', 'tedna', 'tedne', 'tednov') + ' nazaj'; },
12143	monthAgo: 'mesec nazaj',
12144	monthsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'mesec', 'meseca', 'mesece', 'mesecov') + ' nazaj'; },
12145	yearthAgo: 'leto nazaj',
12146	yearsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'leto', 'leti', 'leta', 'let') + ' nazaj'; },
12147
12148	lessThanMinuteUntil: 'še manj kot minuto',
12149	minuteUntil: 'še minuta',
12150	minutesUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'minuta', 'minuti', 'minute', 'minut'); },
12151	hourUntil: 'še ura',
12152	hoursUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'ura', 'uri', 'ure', 'ur'); },
12153	dayUntil: 'še dan',
12154	daysUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'dan', 'dneva', 'dnevi', 'dni'); },
12155	weekUntil: 'še tedn',
12156	weeksUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'teden', 'tedna', 'tedni', 'tednov'); },
12157	monthUntil: 'še mesec',
12158	monthsUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'mesec', 'meseca', 'meseci', 'mesecov'); },
12159	yearUntil: 'še leto',
12160	yearsUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'leto', 'leti', 'leta', 'let'); }
12161
12162});
12163
12164})();
12165
12166/*
12167---
12168
12169name: Locale.si-SI.Form.Validator
12170
12171description: Form Validator messages for Slovenian.
12172
12173license: MIT-style license
12174
12175authors:
12176  - Radovan Lozej
12177
12178requires:
12179  - Locale
12180
12181provides: [Locale.si-SI.Form.Validator]
12182
12183...
12184*/
12185
12186Locale.define('sl-SI', 'FormValidator', {
12187
12188	required: 'To polje je obvezno',
12189	minLength: 'Prosim, vnesite vsaj {minLength} znakov (vnesli ste {length} znakov).',
12190	maxLength: 'Prosim, ne vnesite več kot {maxLength} znakov (vnesli ste {length} znakov).',
12191	integer: 'Prosim, vnesite celo število. Decimalna števila (kot 1,25) niso dovoljena.',
12192	numeric: 'Prosim, vnesite samo numerične vrednosti (kot "1" ali "1.1" ali "-1" ali "-1.1").',
12193	digits: 'Prosim, uporabite številke in ločila le na tem polju (na primer, dovoljena je telefonska številka z pomišlaji ali pikami).',
12194	alpha: 'Prosim, uporabite le črke v tem plju. Presledki in drugi znaki niso dovoljeni.',
12195	alphanum: 'Prosim, uporabite samo črke ali številke v tem polju. Presledki in drugi znaki niso dovoljeni.',
12196	dateSuchAs: 'Prosim, vnesite pravilen datum kot {date}',
12197	dateInFormatMDY: 'Prosim, vnesite pravilen datum kot MM.DD.YYYY (primer "12.31.1999")',
12198	email: 'Prosim, vnesite pravilen email naslov. Na primer "[email protected]".',
12199	url: 'Prosim, vnesite pravilen URL kot http://www.example.com.',
12200	currencyDollar: 'Prosim, vnesit epravilno vrednost €. Primer 100,00€ .',
12201	oneRequired: 'Prosimo, vnesite nekaj za vsaj eno izmed teh polj.',
12202	errorPrefix: 'Napaka: ',
12203	warningPrefix: 'Opozorilo: ',
12204
12205	// Form.Validator.Extras
12206	noSpace: 'To vnosno polje ne dopušča presledkov.',
12207	reqChkByNode: 'Nič niste izbrali.',
12208	requiredChk: 'To polje je obvezno',
12209	reqChkByName: 'Prosim, izberite {label}.',
12210	match: 'To polje se mora ujemati z poljem {matchName}',
12211	startDate: 'datum začetka',
12212	endDate: 'datum konca',
12213	currentDate: 'trenuten datum',
12214	afterDate: 'Datum bi moral biti isti ali po {label}.',
12215	beforeDate: 'Datum bi moral biti isti ali pred {label}.',
12216	startMonth: 'Prosim, vnesite začetni datum',
12217	sameMonth: 'Ta dva datuma morata biti v istem mesecu - premeniti morate eno ali drugo.',
12218	creditcard: 'Številka kreditne kartice ni pravilna. Preverite številko ali poskusite še enkrat. Vnešenih {length} znakov.'
12219
12220});
12221
12222/*
12223---
12224
12225name: Locale.sv-SE.Date
12226
12227description: Date messages for Swedish.
12228
12229license: MIT-style license
12230
12231authors:
12232  - Martin Lundgren
12233
12234requires:
12235  - Locale
12236
12237provides: [Locale.sv-SE.Date]
12238
12239...
12240*/
12241
12242Locale.define('sv-SE', 'Date', {
12243
12244	months: ['januari', 'februari', 'mars', 'april', 'maj', 'juni', 'juli', 'augusti', 'september', 'oktober', 'november', 'december'],
12245	months_abbr: ['jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'],
12246	days: ['söndag', 'måndag', 'tisdag', 'onsdag', 'torsdag', 'fredag', 'lördag'],
12247	days_abbr: ['sön', 'mån', 'tis', 'ons', 'tor', 'fre', 'lör'],
12248
12249	// Culture's date order: YYYY-MM-DD
12250	dateOrder: ['year', 'month', 'date'],
12251	shortDate: '%Y-%m-%d',
12252	shortTime: '%H:%M',
12253	AM: '',
12254	PM: '',
12255	firstDayOfWeek: 1,
12256
12257	// Date.Extras
12258	ordinal: '',
12259
12260	lessThanMinuteAgo: 'mindre än en minut sedan',
12261	minuteAgo: 'ungefär en minut sedan',
12262	minutesAgo: '{delta} minuter sedan',
12263	hourAgo: 'ungefär en timme sedan',
12264	hoursAgo: 'ungefär {delta} timmar sedan',
12265	dayAgo: '1 dag sedan',
12266	daysAgo: '{delta} dagar sedan',
12267
12268	lessThanMinuteUntil: 'mindre än en minut sedan',
12269	minuteUntil: 'ungefär en minut sedan',
12270	minutesUntil: '{delta} minuter sedan',
12271	hourUntil: 'ungefär en timme sedan',
12272	hoursUntil: 'ungefär {delta} timmar sedan',
12273	dayUntil: '1 dag sedan',
12274	daysUntil: '{delta} dagar sedan'
12275
12276});
12277
12278/*
12279---
12280
12281name: Locale.sv-SE.Form.Validator
12282
12283description: Form Validator messages for Swedish.
12284
12285license: MIT-style license
12286
12287authors:
12288  - Martin Lundgren
12289
12290requires:
12291  - Locale
12292
12293provides: [Locale.sv-SE.Form.Validator]
12294
12295...
12296*/
12297
12298Locale.define('sv-SE', 'FormValidator', {
12299
12300	required: 'Fältet är obligatoriskt.',
12301	minLength: 'Ange minst {minLength} tecken (du angav {length} tecken).',
12302	maxLength: 'Ange högst {maxLength} tecken (du angav {length} tecken). ',
12303	integer: 'Ange ett heltal i fältet. Tal med decimaler (t.ex. 1,25) är inte tillåtna.',
12304	numeric: 'Ange endast numeriska värden i detta fält (t.ex. "1" eller "1.1" eller "-1" eller "-1,1").',
12305	digits: 'Använd endast siffror och skiljetecken i detta fält (till exempel ett telefonnummer med bindestreck tillåtet).',
12306	alpha: 'Använd endast bokstäver (a-ö) i detta fält. Inga mellanslag eller andra tecken är tillåtna.',
12307	alphanum: 'Använd endast bokstäver (a-ö) och siffror (0-9) i detta fält. Inga mellanslag eller andra tecken är tillåtna.',
12308	dateSuchAs: 'Ange ett giltigt datum som t.ex. {date}',
12309	dateInFormatMDY: 'Ange ett giltigt datum som t.ex. YYYY-MM-DD (i.e. "1999-12-31")',
12310	email: 'Ange en giltig e-postadress. Till exempel "[email protected]".',
12311	url: 'Ange en giltig webbadress som http://www.example.com.',
12312	currencyDollar: 'Ange en giltig belopp. Exempelvis 100,00.',
12313	oneRequired: 'Vänligen ange minst ett av dessa alternativ.',
12314	errorPrefix: 'Fel: ',
12315	warningPrefix: 'Varning: ',
12316
12317	// Form.Validator.Extras
12318	noSpace: 'Det får inte finnas några mellanslag i detta fält.',
12319	reqChkByNode: 'Inga objekt är valda.',
12320	requiredChk: 'Detta är ett obligatoriskt fält.',
12321	reqChkByName: 'Välj en {label}.',
12322	match: 'Detta fält måste matcha {matchName}',
12323	startDate: 'startdatumet',
12324	endDate: 'slutdatum',
12325	currentDate: 'dagens datum',
12326	afterDate: 'Datumet bör vara samma eller senare än {label}.',
12327	beforeDate: 'Datumet bör vara samma eller tidigare än {label}.',
12328	startMonth: 'Välj en start månad',
12329	sameMonth: 'Dessa två datum måste vara i samma månad - du måste ändra det ena eller det andra.'
12330
12331});
12332
12333/*
12334---
12335
12336name: Locale.sv-SE.Number
12337
12338description: Number messages for Swedish.
12339
12340license: MIT-style license
12341
12342authors:
12343  - Arian Stolwijk
12344  - Martin Lundgren
12345
12346requires:
12347  - Locale
12348  - Locale.EU.Number
12349
12350provides: [Locale.sv-SE.Number]
12351
12352...
12353*/
12354
12355Locale.define('sv-SE', 'Number', {
12356
12357	currency: {
12358		prefix: 'SEK '
12359	}
12360
12361}).inherit('EU', 'Number');
12362
12363/*
12364---
12365
12366name: Locale.tr-TR.Date
12367
12368description: Date messages for Turkish.
12369
12370license: MIT-style license
12371
12372authors:
12373  - Faruk Can Bilir
12374
12375requires:
12376  - Locale
12377
12378provides: [Locale.tr-TR.Date]
12379
12380...
12381*/
12382
12383Locale.define('tr-TR', 'Date', {
12384
12385	months: ['Ocak', 'Şubat', 'Mart', 'Nisan', 'Mayıs', 'Haziran', 'Temmuz', 'Ağustos', 'Eylül', 'Ekim', 'Kasım', 'Aralık'],
12386	months_abbr: ['Oca', 'Şub', 'Mar', 'Nis', 'May', 'Haz', 'Tem', 'Ağu', 'Eyl', 'Eki', 'Kas', 'Ara'],
12387	days: ['Pazar', 'Pazartesi', 'Salı', 'Çarşamba', 'Perşembe', 'Cuma', 'Cumartesi'],
12388	days_abbr: ['Pa', 'Pzt', 'Sa', 'Ça', 'Pe', 'Cu', 'Cmt'],
12389
12390	// Culture's date order: MM/DD/YYYY
12391	dateOrder: ['date', 'month', 'year'],
12392	shortDate: '%d/%m/%Y',
12393	shortTime: '%H.%M',
12394	AM: 'AM',
12395	PM: 'PM',
12396	firstDayOfWeek: 1,
12397
12398	// Date.Extras
12399	ordinal: '',
12400
12401	lessThanMinuteAgo: 'bir dakikadan önce',
12402	minuteAgo: 'yaklaşık bir dakika önce',
12403	minutesAgo: '{delta} dakika önce',
12404	hourAgo: 'bir saat kadar önce',
12405	hoursAgo: '{delta} saat kadar önce',
12406	dayAgo: 'bir gün önce',
12407	daysAgo: '{delta} gün önce',
12408	weekAgo: 'bir hafta önce',
12409	weeksAgo: '{delta} hafta önce',
12410	monthAgo: 'bir ay önce',
12411	monthsAgo: '{delta} ay önce',
12412	yearAgo: 'bir yıl önce',
12413	yearsAgo: '{delta} yıl önce',
12414
12415	lessThanMinuteUntil: 'bir dakikadan az sonra',
12416	minuteUntil: 'bir dakika kadar sonra',
12417	minutesUntil: '{delta} dakika sonra',
12418	hourUntil: 'bir saat kadar sonra',
12419	hoursUntil: '{delta} saat kadar sonra',
12420	dayUntil: 'bir gün sonra',
12421	daysUntil: '{delta} gün sonra',
12422	weekUntil: 'bir hafta sonra',
12423	weeksUntil: '{delta} hafta sonra',
12424	monthUntil: 'bir ay sonra',
12425	monthsUntil: '{delta} ay sonra',
12426	yearUntil: 'bir yıl sonra',
12427	yearsUntil: '{delta} yıl sonra'
12428
12429});
12430
12431/*
12432---
12433
12434name: Locale.tr-TR.Form.Validator
12435
12436description: Form Validator messages for Turkish.
12437
12438license: MIT-style license
12439
12440authors:
12441  - Faruk Can Bilir
12442
12443requires:
12444  - Locale
12445
12446provides: [Locale.tr-TR.Form.Validator]
12447
12448...
12449*/
12450
12451Locale.define('tr-TR', 'FormValidator', {
12452
12453	required: 'Bu alan zorunlu.',
12454	minLength: 'Lütfen en az {minLength} karakter girin (siz {length} karakter girdiniz).',
12455	maxLength: 'Lütfen en fazla {maxLength} karakter girin (siz {length} karakter girdiniz).',
12456	integer: 'Lütfen bu alana sadece tamsayı girin. Ondalıklı sayılar (ör: 1.25) kullanılamaz.',
12457	numeric: 'Lütfen bu alana sadece sayısal değer girin (ör: "1", "1.1", "-1" ya da "-1.1").',
12458	digits: 'Lütfen bu alana sadece sayısal değer ve noktalama işareti girin (örneğin, nokta ve tire içeren bir telefon numarası kullanılabilir).',
12459	alpha: 'Lütfen bu alanda yalnızca harf kullanın. Boşluk ve diğer karakterler kullanılamaz.',
12460	alphanum: 'Lütfen bu alanda sadece harf ve rakam kullanın. Boşluk ve diğer karakterler kullanılamaz.',
12461	dateSuchAs: 'Lütfen geçerli bir tarih girin (Ör: {date})',
12462	dateInFormatMDY: 'Lütfen geçerli bir tarih girin (GG/AA/YYYY, ör: "31/12/1999")',
12463	email: 'Lütfen geçerli bir email adresi girin. Ör: "[email protected]".',
12464	url: 'Lütfen geçerli bir URL girin. Ör: http://www.example.com.',
12465	currencyDollar: 'Lütfen geçerli bir TL miktarı girin. Ör: 100,00 TL .',
12466	oneRequired: 'Lütfen en az bir tanesini doldurun.',
12467	errorPrefix: 'Hata: ',
12468	warningPrefix: 'Uyarı: ',
12469
12470	// Form.Validator.Extras
12471	noSpace: 'Bu alanda boşluk kullanılamaz.',
12472	reqChkByNode: 'Hiçbir öğe seçilmemiş.',
12473	requiredChk: 'Bu alan zorunlu.',
12474	reqChkByName: 'Lütfen bir {label} girin.',
12475	match: 'Bu alan, {matchName} alanıyla uyuşmalı',
12476	startDate: 'başlangıç tarihi',
12477	endDate: 'bitiş tarihi',
12478	currentDate: 'bugünün tarihi',
12479	afterDate: 'Tarih, {label} tarihiyle aynı gün ya da ondan sonra olmalıdır.',
12480	beforeDate: 'Tarih, {label} tarihiyle aynı gün ya da ondan önce olmalıdır.',
12481	startMonth: 'Lütfen bir başlangıç ayı seçin',
12482	sameMonth: 'Bu iki tarih aynı ayda olmalı - bir tanesini değiştirmeniz gerekiyor.',
12483	creditcard: 'Girdiğiniz kredi kartı numarası geçersiz. Lütfen kontrol edip tekrar deneyin. {length} hane girildi.'
12484
12485});
12486
12487/*
12488---
12489
12490name: Locale.tr-TR.Number
12491
12492description: Number messages for Turkish.
12493
12494license: MIT-style license
12495
12496authors:
12497  - Faruk Can Bilir
12498
12499requires:
12500  - Locale
12501  - Locale.EU.Number
12502
12503provides: [Locale.tr-TR.Number]
12504
12505...
12506*/
12507
12508Locale.define('tr-TR', 'Number', {
12509
12510	currency: {
12511		decimals: 0,
12512		suffix: ' TL'
12513	}
12514
12515}).inherit('EU', 'Number');
12516
12517/*
12518---
12519
12520name: Locale.uk-UA.Date
12521
12522description: Date messages for Ukrainian (utf-8).
12523
12524license: MIT-style license
12525
12526authors:
12527  - Slik
12528
12529requires:
12530  - Locale
12531
12532provides: [Locale.uk-UA.Date]
12533
12534...
12535*/
12536
12537(function(){
12538
12539var pluralize = function(n, one, few, many, other){
12540	var d = (n / 10).toInt(),
12541		z = n % 10,
12542		s = (n / 100).toInt();
12543
12544	if (d == 1 && n > 10) return many;
12545	if (z == 1) return one;
12546	if (z > 0 && z < 5) return few;
12547	return many;
12548};
12549
12550Locale.define('uk-UA', 'Date', {
12551
12552	months: ['Січень', 'Лютий', 'Березень', 'Квітень', 'Травень', 'Червень', 'Липень', 'Серпень', 'Вересень', 'Жовтень', 'Листопад', 'Грудень'],
12553	months_abbr: ['Січ', 'Лют', 'Бер', 'Квіт', 'Трав', 'Черв', 'Лип', 'Серп', 'Вер', 'Жовт', 'Лист', 'Груд' ],
12554	days: ['Неділя', 'Понеділок', 'Вівторок', 'Середа', 'Четвер', "П'ятниця", 'Субота'],
12555	days_abbr: ['Нд', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'],
12556
12557	// Culture's date order: DD/MM/YYYY
12558	dateOrder: ['date', 'month', 'year'],
12559	shortDate: '%d/%m/%Y',
12560	shortTime: '%H:%M',
12561	AM: 'до полудня',
12562	PM: 'по полудню',
12563	firstDayOfWeek: 1,
12564
12565	// Date.Extras
12566	ordinal: '',
12567
12568	lessThanMinuteAgo: 'меньше хвилини тому',
12569	minuteAgo: 'хвилину тому',
12570	minutesAgo: function(delta){ return '{delta} ' + pluralize(delta, 'хвилину', 'хвилини', 'хвилин') + ' тому'; },
12571	hourAgo: 'годину тому',
12572	hoursAgo: function(delta){ return '{delta} ' + pluralize(delta, 'годину', 'години', 'годин') + ' тому'; },
12573	dayAgo: 'вчора',
12574	daysAgo: function(delta){ return '{delta} ' + pluralize(delta, 'день', 'дня', 'днів') + ' тому'; },
12575	weekAgo: 'тиждень тому',
12576	weeksAgo: function(delta){ return '{delta} ' + pluralize(delta, 'тиждень', 'тижні', 'тижнів') + ' тому'; },
12577	monthAgo: 'місяць тому',
12578	monthsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'місяць', 'місяці', 'місяців') + ' тому'; },
12579	yearAgo: 'рік тому',
12580	yearsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'рік', 'роки', 'років') + ' тому'; },
12581
12582	lessThanMinuteUntil: 'за мить',
12583	minuteUntil: 'через хвилину',
12584	minutesUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'хвилину', 'хвилини', 'хвилин'); },
12585	hourUntil: 'через годину',
12586	hoursUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'годину', 'години', 'годин'); },
12587	dayUntil: 'завтра',
12588	daysUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'день', 'дня', 'днів'); },
12589	weekUntil: 'через тиждень',
12590	weeksUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'тиждень', 'тижні', 'тижнів'); },
12591	monthUntil: 'через місяць',
12592	monthesUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'місяць', 'місяці', 'місяців'); },
12593	yearUntil: 'через рік',
12594	yearsUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'рік', 'роки', 'років'); }
12595
12596});
12597
12598})();
12599
12600/*
12601---
12602
12603name: Locale.uk-UA.Form.Validator
12604
12605description: Form Validator messages for Ukrainian (utf-8).
12606
12607license: MIT-style license
12608
12609authors:
12610  - Slik
12611
12612requires:
12613  - Locale
12614
12615provides: [Locale.uk-UA.Form.Validator]
12616
12617...
12618*/
12619
12620Locale.define('uk-UA', 'FormValidator', {
12621
12622	required: 'Це поле повинне бути заповненим.',
12623	minLength: 'Введіть хоча б {minLength} символів (Ви ввели {length}).',
12624	maxLength: 'Кількість символів не може бути більше {maxLength} (Ви ввели {length}).',
12625	integer: 'Введіть в це поле число. Дробові числа (наприклад 1.25) не дозволені.',
12626	numeric: 'Введіть в це поле число (наприклад "1" або "1.1", або "-1", або "-1.1").',
12627	digits: 'В цьому полі ви можете використовувати лише цифри і знаки пунктіації (наприклад, телефонний номер з знаками дефізу або з крапками).',
12628	alpha: 'В цьому полі можна використовувати лише латинські літери (a-z). Пробіли і інші символи заборонені.',
12629	alphanum: 'В цьому полі можна використовувати лише латинські літери (a-z) і цифри (0-9). Пробіли і інші символи заборонені.',
12630	dateSuchAs: 'Введіть коректну дату {date}.',
12631	dateInFormatMDY: 'Введіть дату в форматі ММ/ДД/РРРР (наприклад "12/31/2009").',
12632	email: 'Введіть коректну адресу електронної пошти (наприклад "[email protected]").',
12633	url: 'Введіть коректне інтернет-посилання (наприклад http://www.example.com).',
12634	currencyDollar: 'Введіть суму в доларах (наприклад "$100.00").',
12635	oneRequired: 'Заповніть одне з полів.',
12636	errorPrefix: 'Помилка: ',
12637	warningPrefix: 'Увага: ',
12638
12639	noSpace: 'Пробіли заборонені.',
12640	reqChkByNode: 'Не відмічено жодного варіанту.',
12641	requiredChk: 'Це поле повинне бути віміченим.',
12642	reqChkByName: 'Будь ласка, відмітьте {label}.',
12643	match: 'Це поле повинно відповідати {matchName}',
12644	startDate: 'початкова дата',
12645	endDate: 'кінцева дата',
12646	currentDate: 'сьогоднішня дата',
12647	afterDate: 'Ця дата повинна бути такою ж, або пізнішою за {label}.',
12648	beforeDate: 'Ця дата повинна бути такою ж, або ранішою за {label}.',
12649	startMonth: 'Будь ласка, виберіть початковий місяць',
12650	sameMonth: 'Ці дати повинні відноситись одного і того ж місяця. Будь ласка, змініть одну з них.',
12651	creditcard: 'Номер кредитної карти введений неправильно. Будь ласка, перевірте його. Введено {length} символів.'
12652
12653});
12654
12655/*
12656---
12657
12658name: Locale.zh-CH.Date
12659
12660description: Date messages for Chinese (simplified and traditional).
12661
12662license: MIT-style license
12663
12664authors:
12665  - YMind Chan
12666
12667requires:
12668  - Locale
12669
12670provides: [Locale.zh-CH.Date]
12671
12672...
12673*/
12674
12675// Simplified Chinese
12676Locale.define('zh-CHS', 'Date', {
12677
12678	months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
12679	months_abbr: ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'],
12680	days: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
12681	days_abbr: ['日', '一', '二', '三', '四', '五', '六'],
12682
12683	// Culture's date order: YYYY-MM-DD
12684	dateOrder: ['year', 'month', 'date'],
12685	shortDate: '%Y-%m-%d',
12686	shortTime: '%I:%M%p',
12687	AM: 'AM',
12688	PM: 'PM',
12689	firstDayOfWeek: 1,
12690
12691	// Date.Extras
12692	ordinal: '',
12693
12694	lessThanMinuteAgo: '不到1分钟前',
12695	minuteAgo: '大约1分钟前',
12696	minutesAgo: '{delta}分钟之前',
12697	hourAgo: '大约1小时前',
12698	hoursAgo: '大约{delta}小时前',
12699	dayAgo: '1天前',
12700	daysAgo: '{delta}天前',
12701	weekAgo: '1星期前',
12702	weeksAgo: '{delta}星期前',
12703	monthAgo: '1个月前',
12704	monthsAgo: '{delta}个月前',
12705	yearAgo: '1年前',
12706	yearsAgo: '{delta}年前',
12707
12708	lessThanMinuteUntil: '从现在开始不到1分钟',
12709	minuteUntil: '从现在开始約1分钟',
12710	minutesUntil: '从现在开始约{delta}分钟',
12711	hourUntil: '从现在开始1小时',
12712	hoursUntil: '从现在开始约{delta}小时',
12713	dayUntil: '从现在开始1天',
12714	daysUntil: '从现在开始{delta}天',
12715	weekUntil: '从现在开始1星期',
12716	weeksUntil: '从现在开始{delta}星期',
12717	monthUntil: '从现在开始一个月',
12718	monthsUntil: '从现在开始{delta}个月',
12719	yearUntil: '从现在开始1年',
12720	yearsUntil: '从现在开始{delta}年'
12721
12722});
12723
12724// Traditional Chinese
12725Locale.define('zh-CHT', 'Date', {
12726
12727	months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
12728	months_abbr: ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'],
12729	days: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
12730	days_abbr: ['日', '一', '二', '三', '四', '五', '六'],
12731
12732	// Culture's date order: YYYY-MM-DD
12733	dateOrder: ['year', 'month', 'date'],
12734	shortDate: '%Y-%m-%d',
12735	shortTime: '%I:%M%p',
12736	AM: 'AM',
12737	PM: 'PM',
12738	firstDayOfWeek: 1,
12739
12740	// Date.Extras
12741	ordinal: '',
12742
12743	lessThanMinuteAgo: '不到1分鐘前',
12744	minuteAgo: '大約1分鐘前',
12745	minutesAgo: '{delta}分鐘之前',
12746	hourAgo: '大約1小時前',
12747	hoursAgo: '大約{delta}小時前',
12748	dayAgo: '1天前',
12749	daysAgo: '{delta}天前',
12750	weekAgo: '1星期前',
12751	weeksAgo: '{delta}星期前',
12752	monthAgo: '1个月前',
12753	monthsAgo: '{delta}个月前',
12754	yearAgo: '1年前',
12755	yearsAgo: '{delta}年前',
12756
12757	lessThanMinuteUntil: '從現在開始不到1分鐘',
12758	minuteUntil: '從現在開始約1分鐘',
12759	minutesUntil: '從現在開始約{delta}分鐘',
12760	hourUntil: '從現在開始1小時',
12761	hoursUntil: '從現在開始約{delta}小時',
12762	dayUntil: '從現在開始1天',
12763	daysUntil: '從現在開始{delta}天',
12764	weekUntil: '從現在開始1星期',
12765	weeksUntil: '從現在開始{delta}星期',
12766	monthUntil: '從現在開始一個月',
12767	monthsUntil: '從現在開始{delta}個月',
12768	yearUntil: '從現在開始1年',
12769	yearsUntil: '從現在開始{delta}年'
12770
12771});
12772
12773/*
12774---
12775
12776name: Locale.zh-CH.Form.Validator
12777
12778description: Form Validator messages for Chinese (simplified and traditional).
12779
12780license: MIT-style license
12781
12782authors:
12783  - YMind Chan
12784
12785requires:
12786  - Locale
12787  - Form.Validator
12788
12789provides: [Form.zh-CH.Form.Validator, Form.Validator.CurrencyYuanValidator]
12790
12791...
12792*/
12793
12794// Simplified Chinese
12795Locale.define('zh-CHS', 'FormValidator', {
12796
12797	required: '此项必填。',
12798	minLength: '请至少输入 {minLength} 个字符 (已输入 {length} 个)。',
12799	maxLength: '最多只能输入 {maxLength} 个字符 (已输入 {length} 个)。',
12800	integer: '请输入一个整数,不能包含小数点。例如:"1", "200"。',
12801	numeric: '请输入一个数字,例如:"1", "1.1", "-1", "-1.1"。',
12802	digits: '请输入由数字和标点符号组成的内容。例如电话号码。',
12803	alpha: '请输入 A-Z 的 26 个字母,不能包含空格或任何其他字符。',
12804	alphanum: '请输入 A-Z 的 26 个字母或 0-9 的 10 个数字,不能包含空格或任何其他字符。',
12805	dateSuchAs: '请输入合法的日期格式,如:{date}。',
12806	dateInFormatMDY: '请输入合法的日期格式,例如:YYYY-MM-DD ("2010-12-31")。',
12807	email: '请输入合法的电子信箱地址,例如:"[email protected]"。',
12808	url: '请输入合法的 Url 地址,例如:http://www.example.com。',
12809	currencyDollar: '请输入合法的货币符号,例如:¥100.0',
12810	oneRequired: '请至少选择一项。',
12811	errorPrefix: '错误:',
12812	warningPrefix: '警告:',
12813
12814	// Form.Validator.Extras
12815	noSpace: '不能包含空格。',
12816	reqChkByNode: '未选择任何内容。',
12817	requiredChk: '此项必填。',
12818	reqChkByName: '请选择 {label}.',
12819	match: '必须与{matchName}相匹配',
12820	startDate: '起始日期',
12821	endDate: '结束日期',
12822	currentDate: '当前日期',
12823	afterDate: '日期必须等于或晚于 {label}.',
12824	beforeDate: '日期必须早于或等于 {label}.',
12825	startMonth: '请选择起始月份',
12826	sameMonth: '您必须修改两个日期中的一个,以确保它们在同一月份。',
12827	creditcard: '您输入的信用卡号码不正确。当前已输入{length}个字符。'
12828
12829});
12830
12831// Traditional Chinese
12832Locale.define('zh-CHT', 'FormValidator', {
12833
12834	required: '此項必填。 ',
12835	minLength: '請至少輸入{minLength} 個字符(已輸入{length} 個)。 ',
12836	maxLength: '最多只能輸入{maxLength} 個字符(已輸入{length} 個)。 ',
12837	integer: '請輸入一個整數,不能包含小數點。例如:"1", "200"。 ',
12838	numeric: '請輸入一個數字,例如:"1", "1.1", "-1", "-1.1"。 ',
12839	digits: '請輸入由數字和標點符號組成的內容。例如電話號碼。 ',
12840	alpha: '請輸入AZ 的26 個字母,不能包含空格或任何其他字符。 ',
12841	alphanum: '請輸入AZ 的26 個字母或0-9 的10 個數字,不能包含空格或任何其他字符。 ',
12842	dateSuchAs: '請輸入合法的日期格式,如:{date}。 ',
12843	dateInFormatMDY: '請輸入合法的日期格式,例如:YYYY-MM-DD ("2010-12-31")。 ',
12844	email: '請輸入合法的電子信箱地址,例如:"[email protected]"。 ',
12845	url: '請輸入合法的Url 地址,例如:http://www.example.com。 ',
12846	currencyDollar: '請輸入合法的貨幣符號,例如:¥100.0',
12847	oneRequired: '請至少選擇一項。 ',
12848	errorPrefix: '錯誤:',
12849	warningPrefix: '警告:',
12850
12851	// Form.Validator.Extras
12852	noSpace: '不能包含空格。 ',
12853	reqChkByNode: '未選擇任何內容。 ',
12854	requiredChk: '此項必填。 ',
12855	reqChkByName: '請選擇 {label}.',
12856	match: '必須與{matchName}相匹配',
12857	startDate: '起始日期',
12858	endDate: '結束日期',
12859	currentDate: '當前日期',
12860	afterDate: '日期必須等於或晚於{label}.',
12861	beforeDate: '日期必須早於或等於{label}.',
12862	startMonth: '請選擇起始月份',
12863	sameMonth: '您必須修改兩個日期中的一個,以確保它們在同一月份。 ',
12864	creditcard: '您輸入的信用卡號碼不正確。當前已輸入{length}個字符。 '
12865
12866});
12867
12868Form.Validator.add('validate-currency-yuan', {
12869
12870	errorMsg: function(){
12871		return Form.Validator.getMsg('currencyYuan');
12872	},
12873
12874	test: function(element){
12875		// [ï¿¥]1[##][,###]+[.##]
12876		// [ï¿¥]1###+[.##]
12877		// [ï¿¥]0.##
12878		// [ï¿¥].##
12879		return Form.Validator.getValidator('IsEmpty').test(element) || (/^ï¿¥?\-?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/).test(element.get('value'));
12880	}
12881
12882});
12883
12884/*
12885---
12886
12887name: Locale.zh-CH.Number
12888
12889description: Number messages for for Chinese (simplified and traditional).
12890
12891license: MIT-style license
12892
12893authors:
12894  - YMind Chan
12895
12896requires:
12897  - Locale
12898  - Locale.en-US.Number
12899
12900provides: [Locale.zh-CH.Number]
12901
12902...
12903*/
12904
12905// Simplified Chinese
12906Locale.define('zh-CHS', 'Number', {
12907
12908	currency: {
12909		prefix: 'ï¿¥ '
12910	}
12911
12912}).inherit('en-US', 'Number');
12913
12914// Traditional Chinese
12915Locale.define('zh-CHT').inherit('zh-CHS', 'Number');
12916
12917/*
12918---
12919
12920script: Request.JSONP.js
12921
12922name: Request.JSONP
12923
12924description: Defines Request.JSONP, a class for cross domain javascript via script injection.
12925
12926license: MIT-style license
12927
12928authors:
12929  - Aaron Newton
12930  - Guillermo Rauch
12931  - Arian Stolwijk
12932
12933requires:
12934  - Core/Element
12935  - Core/Request
12936  - MooTools.More
12937
12938provides: [Request.JSONP]
12939
12940...
12941*/
12942
12943Request.JSONP = new Class({
12944
12945	Implements: [Chain, Events, Options],
12946
12947	options: {/*
12948		onRequest: function(src, scriptElement){},
12949		onComplete: function(data){},
12950		onSuccess: function(data){},
12951		onCancel: function(){},
12952		onTimeout: function(){},
12953		onError: function(){}, */
12954		onRequest: function(src){
12955			if (this.options.log && window.console && console.log){
12956				console.log('JSONP retrieving script with url:' + src);
12957			}
12958		},
12959		onError: function(src){
12960			if (this.options.log && window.console && console.warn){
12961				console.warn('JSONP '+ src +' will fail in Internet Explorer, which enforces a 2083 bytes length limit on URIs');
12962			}
12963		},
12964		url: '',
12965		callbackKey: 'callback',
12966		injectScript: document.head,
12967		data: '',
12968		link: 'ignore',
12969		timeout: 0,
12970		log: false
12971	},
12972
12973	initialize: function(options){
12974		this.setOptions(options);
12975	},
12976
12977	send: function(options){
12978		if (!Request.prototype.check.call(this, options)) return this;
12979		this.running = true;
12980
12981		var type = typeOf(options);
12982		if (type == 'string' || type == 'element') options = {data: options};
12983		options = Object.merge(this.options, options || {});
12984
12985		var data = options.data;
12986		switch (typeOf(data)){
12987			case 'element': data = document.id(data).toQueryString(); break;
12988			case 'object': case 'hash': data = Object.toQueryString(data);
12989		}
12990
12991		var index = this.index = Request.JSONP.counter++,
12992			key = 'request_' + index;
12993
12994		var src = options.url +
12995			(options.url.test('\\?') ? '&' :'?') +
12996			(options.callbackKey) +
12997			'=Request.JSONP.request_map.request_'+ index +
12998			(data ? '&' + data : '');
12999
13000		if (src.length > 2083) this.fireEvent('error', src);
13001
13002		Request.JSONP.request_map[key] = function(){
13003			delete Request.JSONP.request_map[key];
13004			this.success(arguments, index);
13005		}.bind(this);
13006
13007		var script = this.getScript(src).inject(options.injectScript);
13008		this.fireEvent('request', [src, script]);
13009
13010		if (options.timeout) this.timeout.delay(options.timeout, this);
13011
13012		return this;
13013	},
13014
13015	getScript: function(src){
13016		if (!this.script) this.script = new Element('script', {
13017			type: 'text/javascript',
13018			async: true,
13019			src: src
13020		});
13021		return this.script;
13022	},
13023
13024	success: function(args){
13025		if (!this.running) return;
13026		this.clear()
13027			.fireEvent('complete', args).fireEvent('success', args)
13028			.callChain();
13029	},
13030
13031	cancel: function(){
13032		if (this.running) this.clear().fireEvent('cancel');
13033		return this;
13034	},
13035
13036	isRunning: function(){
13037		return !!this.running;
13038	},
13039
13040	clear: function(){
13041		this.running = false;
13042		if (this.script){
13043			this.script.destroy();
13044			this.script = null;
13045		}
13046		return this;
13047	},
13048
13049	timeout: function(){
13050		if (this.running){
13051			this.running = false;
13052			this.fireEvent('timeout', [this.script.get('src'), this.script]).fireEvent('failure').cancel();
13053		}
13054		return this;
13055	}
13056
13057});
13058
13059Request.JSONP.counter = 0;
13060Request.JSONP.request_map = {};
13061
13062/*
13063---
13064
13065script: Request.Periodical.js
13066
13067name: Request.Periodical
13068
13069description: Requests the same URL to pull data from a server but increases the intervals if no data is returned to reduce the load
13070
13071license: MIT-style license
13072
13073authors:
13074  - Christoph Pojer
13075
13076requires:
13077  - Core/Request
13078  - MooTools.More
13079
13080provides: [Request.Periodical]
13081
13082...
13083*/
13084
13085Request.implement({
13086
13087	options: {
13088		initialDelay: 5000,
13089		delay: 5000,
13090		limit: 60000
13091	},
13092
13093	startTimer: function(data){
13094		var fn = function(){
13095			if (!this.running) this.send({data: data});
13096		};
13097		this.lastDelay = this.options.initialDelay;
13098		this.timer = fn.delay(this.lastDelay, this);
13099		this.completeCheck = function(response){
13100			clearTimeout(this.timer);
13101			this.lastDelay = (response) ? this.options.delay : (this.lastDelay + this.options.delay).min(this.options.limit);
13102			this.timer = fn.delay(this.lastDelay, this);
13103		};
13104		return this.addEvent('complete', this.completeCheck);
13105	},
13106
13107	stopTimer: function(){
13108		clearTimeout(this.timer);
13109		return this.removeEvent('complete', this.completeCheck);
13110	}
13111
13112});
13113
13114/*
13115---
13116
13117script: Request.Queue.js
13118
13119name: Request.Queue
13120
13121description: Controls several instances of Request and its variants to run only one request at a time.
13122
13123license: MIT-style license
13124
13125authors:
13126  - Aaron Newton
13127
13128requires:
13129  - Core/Element
13130  - Core/Request
13131  - Class.Binds
13132
13133provides: [Request.Queue]
13134
13135...
13136*/
13137
13138Request.Queue = new Class({
13139
13140	Implements: [Options, Events],
13141
13142	Binds: ['attach', 'request', 'complete', 'cancel', 'success', 'failure', 'exception'],
13143
13144	options: {/*
13145		onRequest: function(argsPassedToOnRequest){},
13146		onSuccess: function(argsPassedToOnSuccess){},
13147		onComplete: function(argsPassedToOnComplete){},
13148		onCancel: function(argsPassedToOnCancel){},
13149		onException: function(argsPassedToOnException){},
13150		onFailure: function(argsPassedToOnFailure){},
13151		onEnd: function(){},
13152		*/
13153		stopOnFailure: true,
13154		autoAdvance: true,
13155		concurrent: 1,
13156		requests: {}
13157	},
13158
13159	initialize: function(options){
13160		var requests;
13161		if (options){
13162			requests = options.requests;
13163			delete options.requests;
13164		}
13165		this.setOptions(options);
13166		this.requests = {};
13167		this.queue = [];
13168		this.reqBinders = {};
13169
13170		if (requests) this.addRequests(requests);
13171	},
13172
13173	addRequest: function(name, request){
13174		this.requests[name] = request;
13175		this.attach(name, request);
13176		return this;
13177	},
13178
13179	addRequests: function(obj){
13180		Object.each(obj, function(req, name){
13181			this.addRequest(name, req);
13182		}, this);
13183		return this;
13184	},
13185
13186	getName: function(req){
13187		return Object.keyOf(this.requests, req);
13188	},
13189
13190	attach: function(name, req){
13191		if (req._groupSend) return this;
13192		['request', 'complete', 'cancel', 'success', 'failure', 'exception'].each(function(evt){
13193			if (!this.reqBinders[name]) this.reqBinders[name] = {};
13194			this.reqBinders[name][evt] = function(){
13195				this['on' + evt.capitalize()].apply(this, [name, req].append(arguments));
13196			}.bind(this);
13197			req.addEvent(evt, this.reqBinders[name][evt]);
13198		}, this);
13199		req._groupSend = req.send;
13200		req.send = function(options){
13201			this.send(name, options);
13202			return req;
13203		}.bind(this);
13204		return this;
13205	},
13206
13207	removeRequest: function(req){
13208		var name = typeOf(req) == 'object' ? this.getName(req) : req;
13209		if (!name && typeOf(name) != 'string') return this;
13210		req = this.requests[name];
13211		if (!req) return this;
13212		['request', 'complete', 'cancel', 'success', 'failure', 'exception'].each(function(evt){
13213			req.removeEvent(evt, this.reqBinders[name][evt]);
13214		}, this);
13215		req.send = req._groupSend;
13216		delete req._groupSend;
13217		return this;
13218	},
13219
13220	getRunning: function(){
13221		return Object.filter(this.requests, function(r){
13222			return r.running;
13223		});
13224	},
13225
13226	isRunning: function(){
13227		return !!(Object.keys(this.getRunning()).length);
13228	},
13229
13230	send: function(name, options){
13231		var q = function(){
13232			this.requests[name]._groupSend(options);
13233			this.queue.erase(q);
13234		}.bind(this);
13235
13236		q.name = name;
13237		if (Object.keys(this.getRunning()).length >= this.options.concurrent || (this.error && this.options.stopOnFailure)) this.queue.push(q);
13238		else q();
13239		return this;
13240	},
13241
13242	hasNext: function(name){
13243		return (!name) ? !!this.queue.length : !!this.queue.filter(function(q){ return q.name == name; }).length;
13244	},
13245
13246	resume: function(){
13247		this.error = false;
13248		(this.options.concurrent - Object.keys(this.getRunning()).length).times(this.runNext, this);
13249		return this;
13250	},
13251
13252	runNext: function(name){
13253		if (!this.queue.length) return this;
13254		if (!name){
13255			this.queue[0]();
13256		} else {
13257			var found;
13258			this.queue.each(function(q){
13259				if (!found && q.name == name){
13260					found = true;
13261					q();
13262				}
13263			});
13264		}
13265		return this;
13266	},
13267
13268	runAll: function(){
13269		this.queue.each(function(q){
13270			q();
13271		});
13272		return this;
13273	},
13274
13275	clear: function(name){
13276		if (!name){
13277			this.queue.empty();
13278		} else {
13279			this.queue = this.queue.map(function(q){
13280				if (q.name != name) return q;
13281				else return false;
13282			}).filter(function(q){
13283				return q;
13284			});
13285		}
13286		return this;
13287	},
13288
13289	cancel: function(name){
13290		this.requests[name].cancel();
13291		return this;
13292	},
13293
13294	onRequest: function(){
13295		this.fireEvent('request', arguments);
13296	},
13297
13298	onComplete: function(){
13299		this.fireEvent('complete', arguments);
13300		if (!this.queue.length) this.fireEvent('end');
13301	},
13302
13303	onCancel: function(){
13304		if (this.options.autoAdvance && !this.error) this.runNext();
13305		this.fireEvent('cancel', arguments);
13306	},
13307
13308	onSuccess: function(){
13309		if (this.options.autoAdvance && !this.error) this.runNext();
13310		this.fireEvent('success', arguments);
13311	},
13312
13313	onFailure: function(){
13314		this.error = true;
13315		if (!this.options.stopOnFailure && this.options.autoAdvance) this.runNext();
13316		this.fireEvent('failure', arguments);
13317	},
13318
13319	onException: function(){
13320		this.error = true;
13321		if (!this.options.stopOnFailure && this.options.autoAdvance) this.runNext();
13322		this.fireEvent('exception', arguments);
13323	}
13324
13325});
13326
13327/*
13328---
13329
13330script: Array.Extras.js
13331
13332name: Array.Extras
13333
13334description: Extends the Array native object to include useful methods to work with arrays.
13335
13336license: MIT-style license
13337
13338authors:
13339  - Christoph Pojer
13340  - Sebastian Markbåge
13341
13342requires:
13343  - Core/Array
13344  - MooTools.More
13345
13346provides: [Array.Extras]
13347
13348...
13349*/
13350
13351(function(nil){
13352
13353Array.implement({
13354
13355	min: function(){
13356		return Math.min.apply(null, this);
13357	},
13358
13359	max: function(){
13360		return Math.max.apply(null, this);
13361	},
13362
13363	average: function(){
13364		return this.length ? this.sum() / this.length : 0;
13365	},
13366
13367	sum: function(){
13368		var result = 0, l = this.length;
13369		if (l){
13370			while (l--){
13371				if (this[l] != null) result += parseFloat(this[l]);
13372			}
13373		}
13374		return result;
13375	},
13376
13377	unique: function(){
13378		return [].combine(this);
13379	},
13380
13381	shuffle: function(){
13382		for (var i = this.length; i && --i;){
13383			var temp = this[i], r = Math.floor(Math.random() * ( i + 1 ));
13384			this[i] = this[r];
13385			this[r] = temp;
13386		}
13387		return this;
13388	},
13389
13390	reduce: function(fn, value){
13391		for (var i = 0, l = this.length; i < l; i++){
13392			if (i in this) value = value === nil ? this[i] : fn.call(null, value, this[i], i, this);
13393		}
13394		return value;
13395	},
13396
13397	reduceRight: function(fn, value){
13398		var i = this.length;
13399		while (i--){
13400			if (i in this) value = value === nil ? this[i] : fn.call(null, value, this[i], i, this);
13401		}
13402		return value;
13403	},
13404
13405	pluck: function(prop){
13406		return this.map(function(item){
13407			return item[prop];
13408		});
13409	}
13410
13411});
13412
13413})();
13414
13415/*
13416---
13417
13418script: Date.Extras.js
13419
13420name: Date.Extras
13421
13422description: Extends the Date native object to include extra methods (on top of those in Date.js).
13423
13424license: MIT-style license
13425
13426authors:
13427  - Aaron Newton
13428  - Scott Kyle
13429
13430requires:
13431  - Date
13432
13433provides: [Date.Extras]
13434
13435...
13436*/
13437
13438Date.implement({
13439
13440	timeDiffInWords: function(to){
13441		return Date.distanceOfTimeInWords(this, to || new Date);
13442	},
13443
13444	timeDiff: function(to, separator){
13445		if (to == null) to = new Date;
13446		var delta = ((to - this) / 1000).floor().abs();
13447
13448		var vals = [],
13449			durations = [60, 60, 24, 365, 0],
13450			names = ['s', 'm', 'h', 'd', 'y'],
13451			value, duration;
13452
13453		for (var item = 0; item < durations.length; item++){
13454			if (item && !delta) break;
13455			value = delta;
13456			if ((duration = durations[item])){
13457				value = (delta % duration);
13458				delta = (delta / duration).floor();
13459			}
13460			vals.unshift(value + (names[item] || ''));
13461		}
13462
13463		return vals.join(separator || ':');
13464	}
13465
13466}).extend({
13467
13468	distanceOfTimeInWords: function(from, to){
13469		return Date.getTimePhrase(((to - from) / 1000).toInt());
13470	},
13471
13472	getTimePhrase: function(delta){
13473		var suffix = (delta < 0) ? 'Until' : 'Ago';
13474		if (delta < 0) delta *= -1;
13475
13476		var units = {
13477			minute: 60,
13478			hour: 60,
13479			day: 24,
13480			week: 7,
13481			month: 52 / 12,
13482			year: 12,
13483			eon: Infinity
13484		};
13485
13486		var msg = 'lessThanMinute';
13487
13488		for (var unit in units){
13489			var interval = units[unit];
13490			if (delta < 1.5 * interval){
13491				if (delta > 0.75 * interval) msg = unit;
13492				break;
13493			}
13494			delta /= interval;
13495			msg = unit + 's';
13496		}
13497
13498		delta = delta.round();
13499		return Date.getMsg(msg + suffix, delta).substitute({delta: delta});
13500	}
13501
13502}).defineParsers(
13503
13504	{
13505		// "today", "tomorrow", "yesterday"
13506		re: /^(?:tod|tom|yes)/i,
13507		handler: function(bits){
13508			var d = new Date().clearTime();
13509			switch (bits[0]){
13510				case 'tom': return d.increment();
13511				case 'yes': return d.decrement();
13512				default: return d;
13513			}
13514		}
13515	},
13516
13517	{
13518		// "next Wednesday", "last Thursday"
13519		re: /^(next|last) ([a-z]+)$/i,
13520		handler: function(bits){
13521			var d = new Date().clearTime();
13522			var day = d.getDay();
13523			var newDay = Date.parseDay(bits[2], true);
13524			var addDays = newDay - day;
13525			if (newDay <= day) addDays += 7;
13526			if (bits[1] == 'last') addDays -= 7;
13527			return d.set('date', d.getDate() + addDays);
13528		}
13529	}
13530
13531).alias('timeAgoInWords', 'timeDiffInWords');
13532
13533/*
13534---
13535
13536name: Hash
13537
13538description: Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects.
13539
13540license: MIT-style license.
13541
13542requires:
13543  - Core/Object
13544  - MooTools.More
13545
13546provides: [Hash]
13547
13548...
13549*/
13550
13551(function(){
13552
13553if (this.Hash) return;
13554
13555var Hash = this.Hash = new Type('Hash', function(object){
13556	if (typeOf(object) == 'hash') object = Object.clone(object.getClean());
13557	for (var key in object) this[key] = object[key];
13558	return this;
13559});
13560
13561this.$H = function(object){
13562	return new Hash(object);
13563};
13564
13565Hash.implement({
13566
13567	forEach: function(fn, bind){
13568		Object.forEach(this, fn, bind);
13569	},
13570
13571	getClean: function(){
13572		var clean = {};
13573		for (var key in this){
13574			if (this.hasOwnProperty(key)) clean[key] = this[key];
13575		}
13576		return clean;
13577	},
13578
13579	getLength: function(){
13580		var length = 0;
13581		for (var key in this){
13582			if (this.hasOwnProperty(key)) length++;
13583		}
13584		return length;
13585	}
13586
13587});
13588
13589Hash.alias('each', 'forEach');
13590
13591Hash.implement({
13592
13593	has: Object.prototype.hasOwnProperty,
13594
13595	keyOf: function(value){
13596		return Object.keyOf(this, value);
13597	},
13598
13599	hasValue: function(value){
13600		return Object.contains(this, value);
13601	},
13602
13603	extend: function(properties){
13604		Hash.each(properties || {}, function(value, key){
13605			Hash.set(this, key, value);
13606		}, this);
13607		return this;
13608	},
13609
13610	combine: function(properties){
13611		Hash.each(properties || {}, function(value, key){
13612			Hash.include(this, key, value);
13613		}, this);
13614		return this;
13615	},
13616
13617	erase: function(key){
13618		if (this.hasOwnProperty(key)) delete this[key];
13619		return this;
13620	},
13621
13622	get: function(key){
13623		return (this.hasOwnProperty(key)) ? this[key] : null;
13624	},
13625
13626	set: function(key, value){
13627		if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
13628		return this;
13629	},
13630
13631	empty: function(){
13632		Hash.each(this, function(value, key){
13633			delete this[key];
13634		}, this);
13635		return this;
13636	},
13637
13638	include: function(key, value){
13639		if (this[key] == undefined) this[key] = value;
13640		return this;
13641	},
13642
13643	map: function(fn, bind){
13644		return new Hash(Object.map(this, fn, bind));
13645	},
13646
13647	filter: function(fn, bind){
13648		return new Hash(Object.filter(this, fn, bind));
13649	},
13650
13651	every: function(fn, bind){
13652		return Object.every(this, fn, bind);
13653	},
13654
13655	some: function(fn, bind){
13656		return Object.some(this, fn, bind);
13657	},
13658
13659	getKeys: function(){
13660		return Object.keys(this);
13661	},
13662
13663	getValues: function(){
13664		return Object.values(this);
13665	},
13666
13667	toQueryString: function(base){
13668		return Object.toQueryString(this, base);
13669	}
13670
13671});
13672
13673Hash.alias({indexOf: 'keyOf', contains: 'hasValue'});
13674
13675
13676})();
13677
13678
13679/*
13680---
13681
13682script: Hash.Extras.js
13683
13684name: Hash.Extras
13685
13686description: Extends the Hash Type to include getFromPath which allows a path notation to child elements.
13687
13688license: MIT-style license
13689
13690authors:
13691  - Aaron Newton
13692
13693requires:
13694  - Hash
13695  - Object.Extras
13696
13697provides: [Hash.Extras]
13698
13699...
13700*/
13701
13702Hash.implement({
13703
13704	getFromPath: function(notation){
13705		return Object.getFromPath(this, notation);
13706	},
13707
13708	cleanValues: function(method){
13709		return new Hash(Object.cleanValues(this, method));
13710	},
13711
13712	run: function(){
13713		Object.run(arguments);
13714	}
13715
13716});
13717
13718/*
13719---
13720name: Number.Format
13721description: Extends the Number Type object to include a number formatting method.
13722license: MIT-style license
13723authors: [Arian Stolwijk]
13724requires: [Core/Number, Locale.en-US.Number]
13725# Number.Extras is for compatibility
13726provides: [Number.Format, Number.Extras]
13727...
13728*/
13729
13730
13731Number.implement({
13732
13733	format: function(options){
13734		// Thanks dojo and YUI for some inspiration
13735		var value = this;
13736		options = options ? Object.clone(options) : {};
13737		var getOption = function(key){
13738			if (options[key] != null) return options[key];
13739			return Locale.get('Number.' + key);
13740		};
13741
13742		var negative = value < 0,
13743			decimal = getOption('decimal'),
13744			precision = getOption('precision'),
13745			group = getOption('group'),
13746			decimals = getOption('decimals');
13747
13748		if (negative){
13749			var negativeLocale = getOption('negative') || {};
13750			if (negativeLocale.prefix == null && negativeLocale.suffix == null) negativeLocale.prefix = '-';
13751			['prefix', 'suffix'].each(function(key){
13752				if (negativeLocale[key]) options[key] = getOption(key) + negativeLocale[key];
13753			});
13754
13755			value = -value;
13756		}
13757
13758		var prefix = getOption('prefix'),
13759			suffix = getOption('suffix');
13760
13761		if (decimals !== '' && decimals >= 0 && decimals <= 20) value = value.toFixed(decimals);
13762		if (precision >= 1 && precision <= 21) value = (+value).toPrecision(precision);
13763
13764		value += '';
13765		var index;
13766		if (getOption('scientific') === false && value.indexOf('e') > -1){
13767			var match = value.split('e'),
13768				zeros = +match[1];
13769			value = match[0].replace('.', '');
13770
13771			if (zeros < 0){
13772				zeros = -zeros - 1;
13773				index = match[0].indexOf('.');
13774				if (index > -1) zeros -= index - 1;
13775				while (zeros--) value = '0' + value;
13776				value = '0.' + value;
13777			} else {
13778				index = match[0].lastIndexOf('.');
13779				if (index > -1) zeros -= match[0].length - index - 1;
13780				while (zeros--) value += '0';
13781			}
13782		}
13783
13784		if (decimal != '.') value = value.replace('.', decimal);
13785
13786		if (group){
13787			index = value.lastIndexOf(decimal);
13788			index = (index > -1) ? index : value.length;
13789			var newOutput = value.substring(index),
13790				i = index;
13791
13792			while (i--){
13793				if ((index - i - 1) % 3 == 0 && i != (index - 1)) newOutput = group + newOutput;
13794				newOutput = value.charAt(i) + newOutput;
13795			}
13796
13797			value = newOutput;
13798		}
13799
13800		if (prefix) value = prefix + value;
13801		if (suffix) value += suffix;
13802
13803		return value;
13804	},
13805
13806	formatCurrency: function(decimals){
13807		var locale = Locale.get('Number.currency') || {};
13808		if (locale.scientific == null) locale.scientific = false;
13809		locale.decimals = decimals != null ? decimals
13810			: (locale.decimals == null ? 2 : locale.decimals);
13811
13812		return this.format(locale);
13813	},
13814
13815	formatPercentage: function(decimals){
13816		var locale = Locale.get('Number.percentage') || {};
13817		if (locale.suffix == null) locale.suffix = '%';
13818		locale.decimals = decimals != null ? decimals
13819			: (locale.decimals == null ? 2 : locale.decimals);
13820
13821		return this.format(locale);
13822	}
13823
13824});
13825
13826/*
13827---
13828
13829script: URI.js
13830
13831name: URI
13832
13833description: Provides methods useful in managing the window location and uris.
13834
13835license: MIT-style license
13836
13837authors:
13838  - Sebastian Markbåge
13839  - Aaron Newton
13840
13841requires:
13842  - Core/Object
13843  - Core/Class
13844  - Core/Class.Extras
13845  - Core/Element
13846  - String.QueryString
13847
13848provides: [URI]
13849
13850...
13851*/
13852
13853(function(){
13854
13855var toString = function(){
13856	return this.get('value');
13857};
13858
13859var URI = this.URI = new Class({
13860
13861	Implements: Options,
13862
13863	options: {
13864		/*base: false*/
13865	},
13866
13867	regex: /^(?:(\w+):)?(?:\/\/(?:(?:([^:@\/]*):?([^:@\/]*))?@)?(\[[A-Fa-f0-9:]+\]|[^:\/?#]*)(?::(\d*))?)?(\.\.?$|(?:[^?#\/]*\/)*)([^?#]*)(?:\?([^#]*))?(?:#(.*))?/,
13868	parts: ['scheme', 'user', 'password', 'host', 'port', 'directory', 'file', 'query', 'fragment'],
13869	schemes: {http: 80, https: 443, ftp: 21, rtsp: 554, mms: 1755, file: 0},
13870
13871	initialize: function(uri, options){
13872		this.setOptions(options);
13873		var base = this.options.base || URI.base;
13874		if (!uri) uri = base;
13875
13876		if (uri && uri.parsed) this.parsed = Object.clone(uri.parsed);
13877		else this.set('value', uri.href || uri.toString(), base ? new URI(base) : false);
13878	},
13879
13880	parse: function(value, base){
13881		var bits = value.match(this.regex);
13882		if (!bits) return false;
13883		bits.shift();
13884		return this.merge(bits.associate(this.parts), base);
13885	},
13886
13887	merge: function(bits, base){
13888		if ((!bits || !bits.scheme) && (!base || !base.scheme)) return false;
13889		if (base){
13890			this.parts.every(function(part){
13891				if (bits[part]) return false;
13892				bits[part] = base[part] || '';
13893				return true;
13894			});
13895		}
13896		bits.port = bits.port || this.schemes[bits.scheme.toLowerCase()];
13897		bits.directory = bits.directory ? this.parseDirectory(bits.directory, base ? base.directory : '') : '/';
13898		return bits;
13899	},
13900
13901	parseDirectory: function(directory, baseDirectory){
13902		directory = (directory.substr(0, 1) == '/' ? '' : (baseDirectory || '/')) + directory;
13903		if (!directory.test(URI.regs.directoryDot)) return directory;
13904		var result = [];
13905		directory.replace(URI.regs.endSlash, '').split('/').each(function(dir){
13906			if (dir == '..' && result.length > 0) result.pop();
13907			else if (dir != '.') result.push(dir);
13908		});
13909		return result.join('/') + '/';
13910	},
13911
13912	combine: function(bits){
13913		return bits.value || bits.scheme + '://' +
13914			(bits.user ? bits.user + (bits.password ? ':' + bits.password : '') + '@' : '') +
13915			(bits.host || '') + (bits.port && bits.port != this.schemes[bits.scheme] ? ':' + bits.port : '') +
13916			(bits.directory || '/') + (bits.file || '') +
13917			(bits.query ? '?' + bits.query : '') +
13918			(bits.fragment ? '#' + bits.fragment : '');
13919	},
13920
13921	set: function(part, value, base){
13922		if (part == 'value'){
13923			var scheme = value.match(URI.regs.scheme);
13924			if (scheme) scheme = scheme[1];
13925			if (scheme && this.schemes[scheme.toLowerCase()] == null) this.parsed = { scheme: scheme, value: value };
13926			else this.parsed = this.parse(value, (base || this).parsed) || (scheme ? { scheme: scheme, value: value } : { value: value });
13927		} else if (part == 'data'){
13928			this.setData(value);
13929		} else {
13930			this.parsed[part] = value;
13931		}
13932		return this;
13933	},
13934
13935	get: function(part, base){
13936		switch (part){
13937			case 'value': return this.combine(this.parsed, base ? base.parsed : false);
13938			case 'data' : return this.getData();
13939		}
13940		return this.parsed[part] || '';
13941	},
13942
13943	go: function(){
13944		document.location.href = this.toString();
13945	},
13946
13947	toURI: function(){
13948		return this;
13949	},
13950
13951	getData: function(key, part){
13952		var qs = this.get(part || 'query');
13953		if (!(qs || qs === 0)) return key ? null : {};
13954		var obj = qs.parseQueryString();
13955		return key ? obj[key] : obj;
13956	},
13957
13958	setData: function(values, merge, part){
13959		if (typeof values == 'string'){
13960			var data = this.getData();
13961			data[arguments[0]] = arguments[1];
13962			values = data;
13963		} else if (merge){
13964			values = Object.merge(this.getData(null, part), values);
13965		}
13966		return this.set(part || 'query', Object.toQueryString(values));
13967	},
13968
13969	clearData: function(part){
13970		return this.set(part || 'query', '');
13971	},
13972
13973	toString: toString,
13974	valueOf: toString
13975
13976});
13977
13978URI.regs = {
13979	endSlash: /\/$/,
13980	scheme: /^(\w+):/,
13981	directoryDot: /\.\/|\.$/
13982};
13983
13984URI.base = new URI(Array.convert(document.getElements('base[href]', true)).getLast(), {base: document.location});
13985
13986String.implement({
13987
13988	toURI: function(options){
13989		return new URI(this, options);
13990	}
13991
13992});
13993
13994})();
13995
13996/*
13997---
13998
13999script: URI.Relative.js
14000
14001name: URI.Relative
14002
14003description: Extends the URI class to add methods for computing relative and absolute urls.
14004
14005license: MIT-style license
14006
14007authors:
14008  - Sebastian Markbåge
14009
14010
14011requires:
14012  - Class.refactor
14013  - URI
14014
14015provides: [URI.Relative]
14016
14017...
14018*/
14019
14020URI = Class.refactor(URI, {
14021
14022	combine: function(bits, base){
14023		if (!base || bits.scheme != base.scheme || bits.host != base.host || bits.port != base.port)
14024			return this.previous.apply(this, arguments);
14025		var end = bits.file + (bits.query ? '?' + bits.query : '') + (bits.fragment ? '#' + bits.fragment : '');
14026
14027		if (!base.directory) return (bits.directory || (bits.file ? '' : './')) + end;
14028
14029		var baseDir = base.directory.split('/'),
14030			relDir = bits.directory.split('/'),
14031			path = '',
14032			offset;
14033
14034		var i = 0;
14035		for (offset = 0; offset < baseDir.length && offset < relDir.length && baseDir[offset] == relDir[offset]; offset++);
14036		for (i = 0; i < baseDir.length - offset - 1; i++) path += '../';
14037		for (i = offset; i < relDir.length - 1; i++) path += relDir[i] + '/';
14038
14039		return (path || (bits.file ? '' : './')) + end;
14040	},
14041
14042	toAbsolute: function(base){
14043		base = new URI(base);
14044		if (base) base.set('directory', '').set('file', '');
14045		return this.toRelative(base);
14046	},
14047
14048	toRelative: function(base){
14049		return this.get('value', new URI(base));
14050	}
14051
14052});
14053
14054/*
14055---
14056
14057script: Assets.js
14058
14059name: Assets
14060
14061description: Provides methods to dynamically load JavaScript, CSS, and Image files into the document.
14062
14063license: MIT-style license
14064
14065authors:
14066  - Valerio Proietti
14067
14068requires:
14069  - Core/Element.Event
14070  - MooTools.More
14071
14072provides: [Assets, Asset.javascript, Asset.css, Asset.image, Asset.images]
14073
14074...
14075*/
14076;(function(){
14077
14078var Asset = this.Asset = {
14079
14080	javascript: function(source, properties){
14081		if (!properties) properties = {};
14082
14083		var script = new Element('script', {src: source, type: 'text/javascript'}),
14084			doc = properties.document || document,
14085			load = properties.onload || properties.onLoad;
14086
14087		delete properties.onload;
14088		delete properties.onLoad;
14089		delete properties.document;
14090
14091		if (load){
14092			if (!script.addEventListener){
14093				script.addEvent('readystatechange', function(){
14094					if (['loaded', 'complete'].contains(this.readyState)) load.call(this);
14095				});
14096			} else {
14097				script.addEvent('load', load);
14098			}
14099		}
14100
14101		return script.set(properties).inject(doc.head);
14102	},
14103
14104	css: function(source, properties){
14105		if (!properties) properties = {};
14106
14107		var load = properties.onload || properties.onLoad,
14108			doc = properties.document || document,
14109			timeout = properties.timeout || 3000;
14110
14111		['onload', 'onLoad', 'document'].each(function(prop){
14112			delete properties[prop];
14113		});
14114
14115		var link = new Element('link', {
14116			type: 'text/css',
14117			rel: 'stylesheet',
14118			media: 'screen',
14119			href: source
14120		}).setProperties(properties).inject(doc.head);
14121
14122		if (load){
14123			// based on article at http://www.yearofmoo.com/2011/03/cross-browser-stylesheet-preloading.html
14124			var loaded = false, retries = 0;
14125			var check = function(){
14126				var stylesheets = document.styleSheets;
14127				for (var i = 0; i < stylesheets.length; i++){
14128					var file = stylesheets[i];
14129					var owner = file.ownerNode ? file.ownerNode : file.owningElement;
14130					if (owner && owner == link){
14131						loaded = true;
14132						return load.call(link);
14133					}
14134				}
14135				retries++;
14136				if (!loaded && retries < timeout / 50) return setTimeout(check, 50);
14137			};
14138			setTimeout(check, 0);
14139		}
14140		return link;
14141	},
14142
14143	image: function(source, properties){
14144		if (!properties) properties = {};
14145
14146		var image = new Image(),
14147			element = document.id(image) || new Element('img');
14148
14149		['load', 'abort', 'error'].each(function(name){
14150			var type = 'on' + name,
14151				cap = 'on' + name.capitalize(),
14152				event = properties[type] || properties[cap] || function(){};
14153
14154			delete properties[cap];
14155			delete properties[type];
14156
14157			image[type] = function(){
14158				if (!image) return;
14159				if (!element.parentNode){
14160					element.width = image.width;
14161					element.height = image.height;
14162				}
14163				image = image.onload = image.onabort = image.onerror = null;
14164				event.delay(1, element, element);
14165				element.fireEvent(name, element, 1);
14166			};
14167		});
14168
14169		image.src = element.src = source;
14170		if (image && image.complete) image.onload.delay(1);
14171		return element.set(properties);
14172	},
14173
14174	images: function(sources, options){
14175		sources = Array.convert(sources);
14176
14177		var fn = function(){},
14178			counter = 0;
14179
14180		options = Object.merge({
14181			onComplete: fn,
14182			onProgress: fn,
14183			onError: fn,
14184			properties: {}
14185		}, options);
14186
14187		return new Elements(sources.map(function(source, index){
14188			return Asset.image(source, Object.append(options.properties, {
14189				onload: function(){
14190					counter++;
14191					options.onProgress.call(this, counter, index, source);
14192					if (counter == sources.length) options.onComplete();
14193				},
14194				onerror: function(){
14195					counter++;
14196					options.onError.call(this, counter, index, source);
14197					if (counter == sources.length) options.onComplete();
14198				}
14199			}));
14200		}));
14201	}
14202
14203};
14204
14205}
14205)();
14206
14207/*
14208---
14209
14210script: Color.js
14211
14212name: Color
14213
14214description: Class for creating and manipulating colors in JavaScript. Supports HSB -> RGB Conversions and vice versa.
14215
14216license: MIT-style license
14217
14218authors:
14219  - Valerio Proietti
14220
14221requires:
14222  - Core/Array
14223  - Core/String
14224  - Core/Number
14225  - Core/Hash
14226  - Core/Function
14227  - MooTools.More
14228
14229provides: [Color]
14230
14231...
14232*/
14233
14234(function(){
14235
14236var Color = this.Color = new Type('Color', function(color, type){
14237	if (arguments.length >= 3){
14238		type = 'rgb'; color = Array.slice(arguments, 0, 3);
14239	} else if (typeof color == 'string'){
14240		if (color.match(/rgb/)) color = color.rgbToHex().hexToRgb(true);
14241		else if (color.match(/hsb/)) color = color.hsbToRgb();
14242		else color = color.hexToRgb(true);
14243	}
14244	type = type || 'rgb';
14245	switch (type){
14246		case 'hsb':
14247			var old = color;
14248			color = color.hsbToRgb();
14249			color.hsb = old;
14250			break;
14251		case 'hex': color = color.hexToRgb(true); break;
14252	}
14253	color.rgb = color.slice(0, 3);
14254	color.hsb = color.hsb || color.rgbToHsb();
14255	color.hex = color.rgbToHex();
14256	return Object.append(color, this);
14257});
14258
14259Color.implement({
14260
14261	mix: function(){
14262		var colors = Array.slice(arguments);
14263		var alpha = (typeOf(colors.getLast()) == 'number') ? colors.pop() : 50;
14264		var rgb = this.slice();
14265		colors.each(function(color){
14266			color = new Color(color);
14267			for (var i = 0; i < 3; i++) rgb[i] = Math.round((rgb[i] / 100 * (100 - alpha)) + (color[i] / 100 * alpha));
14268		});
14269		return new Color(rgb, 'rgb');
14270	},
14271
14272	invert: function(){
14273		return new Color(this.map(function(value){
14274			return 255 - value;
14275		}));
14276	},
14277
14278	setHue: function(value){
14279		return new Color([value, this.hsb[1], this.hsb[2]], 'hsb');
14280	},
14281
14282	setSaturation: function(percent){
14283		return new Color([this.hsb[0], percent, this.hsb[2]], 'hsb');
14284	},
14285
14286	setBrightness: function(percent){
14287		return new Color([this.hsb[0], this.hsb[1], percent], 'hsb');
14288	}
14289
14290});
14291
14292this.$RGB = function(r, g, b){
14293	return new Color([r, g, b], 'rgb');
14294};
14295
14296this.$HSB = function(h, s, b){
14297	return new Color([h, s, b], 'hsb');
14298};
14299
14300this.$HEX = function(hex){
14301	return new Color(hex, 'hex');
14302};
14303
14304Array.implement({
14305
14306	rgbToHsb: function(){
14307		var red = this[0],
14308			green = this[1],
14309			blue = this[2],
14310			hue = 0,
14311			max = Math.max(red, green, blue),
14312			min = Math.min(red, green, blue),
14313			delta = max - min,
14314			brightness = max / 255,
14315			saturation = (max != 0) ? delta / max : 0;
14316
14317		if (saturation != 0){
14318			var rr = (max - red) / delta;
14319			var gr = (max - green) / delta;
14320			var br = (max - blue) / delta;
14321			if (red == max) hue = br - gr;
14322			else if (green == max) hue = 2 + rr - br;
14323			else hue = 4 + gr - rr;
14324			hue /= 6;
14325			if (hue < 0) hue++;
14326		}
14327		return [Math.round(hue * 360), Math.round(saturation * 100), Math.round(brightness * 100)];
14328	},
14329
14330	hsbToRgb: function(){
14331		var br = Math.round(this[2] / 100 * 255);
14332		if (this[1] == 0){
14333			return [br, br, br];
14334		} else {
14335			var hue = this[0] % 360;
14336			var f = hue % 60;
14337			var p = Math.round((this[2] * (100 - this[1])) / 10000 * 255);
14338			var q = Math.round((this[2] * (6000 - this[1] * f)) / 600000 * 255);
14339			var t = Math.round((this[2] * (6000 - this[1] * (60 - f))) / 600000 * 255);
14340			switch (Math.floor(hue / 60)){
14341				case 0: return [br, t, p];
14342				case 1: return [q, br, p];
14343				case 2: return [p, br, t];
14344				case 3: return [p, q, br];
14345				case 4: return [t, p, br];
14346				case 5: return [br, p, q];
14347			}
14348		}
14349		return false;
14350	}
14351
14352});
14353
14354String.implement({
14355
14356	rgbToHsb: function(){
14357		var rgb = this.match(/\d{1,3}/g);
14358		return (rgb) ? rgb.rgbToHsb() : null;
14359	},
14360
14361	hsbToRgb: function(){
14362		var hsb = this.match(/\d{1,3}/g);
14363		return (hsb) ? hsb.hsbToRgb() : null;
14364	}
14365
14366});
14367
14368})();
14369
14370
14371/*
14372---
14373
14374script: Group.js
14375
14376name: Group
14377
14378description: Class for monitoring collections of events
14379
14380license: MIT-style license
14381
14382authors:
14383  - Valerio Proietti
14384
14385requires:
14386  - Core/Events
14387  - MooTools.More
14388
14389provides: [Group]
14390
14391...
14392*/
14393
14394(function(){
14395
14396var Group = this.Group = new Class({
14397
14398	initialize: function(){
14399		this.instances = Array.flatten(arguments);
14400	},
14401
14402	addEvent: function(type, fn){
14403		var instances = this.instances,
14404			len = instances.length,
14405			togo = len,
14406			args = new Array(len),
14407			self = this;
14408
14409		instances.each(function(instance, i){
14410			instance.addEvent(type, function(){
14411				if (!args[i]) togo--;
14412				args[i] = arguments;
14413				if (!togo){
14414					fn.call(self, instances, instance, args);
14415					togo = len;
14416					args = new Array(len);
14417				}
14418			});
14419		});
14420	}
14421
14422});
14423
14424})();
14425
14426/*
14427---
14428
14429script: Hash.Cookie.js
14430
14431name: Hash.Cookie
14432
14433description: Class for creating, reading, and deleting Cookies in JSON format.
14434
14435license: MIT-style license
14436
14437authors:
14438  - Valerio Proietti
14439  - Aaron Newton
14440
14441requires:
14442  - Core/Cookie
14443  - Core/JSON
14444  - MooTools.More
14445  - Hash
14446
14447provides: [Hash.Cookie]
14448
14449...
14450*/
14451
14452Hash.Cookie = new Class({
14453
14454	Extends: Cookie,
14455
14456	options: {
14457		autoSave: true
14458	},
14459
14460	initialize: function(name, options){
14461		this.parent(name, options);
14462		this.load();
14463	},
14464
14465	save: function(){
14466		var value = JSON.encode(this.hash);
14467		if (!value || value.length > 4096) return false; //cookie would be truncated!
14468		if (value == '{}') this.dispose();
14469		else this.write(value);
14470		return true;
14471	},
14472
14473	load: function(){
14474		this.hash = new Hash(JSON.decode(this.read(), true));
14475		return this;
14476	}
14477
14478});
14479
14480Hash.each(Hash.prototype, function(method, name){
14481	if (typeof method == 'function') Hash.Cookie.implement(name, function(){
14482		var value = method.apply(this.hash, arguments);
14483		if (this.options.autoSave) this.save();
14484		return value;
14485	});
14486});
14487
14488/*
14489---
14490
14491name: Swiff
14492
14493description: Wrapper for embedding SWF movies. Supports External Interface Communication.
14494
14495license: MIT-style license.
14496
14497credits:
14498  - Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject.
14499
14500requires: [Core/Options, Core/Object, Core/Element]
14501
14502provides: Swiff
14503
14504...
14505*/
14506
14507(function(){
14508
14509var Swiff = this.Swiff = new Class({
14510
14511	Implements: Options,
14512
14513	options: {
14514		id: null,
14515		height: 1,
14516		width: 1,
14517		container: null,
14518		properties: {},
14519		params: {
14520			quality: 'high',
14521			allowScriptAccess: 'always',
14522			wMode: 'window',
14523			swLiveConnect: true
14524		},
14525		callBacks: {},
14526		vars: {}
14527	},
14528
14529	toElement: function(){
14530		return this.object;
14531	},
14532
14533	initialize: function(path, options){
14534		this.instance = 'Swiff_' + String.uniqueID();
14535
14536		this.setOptions(options);
14537		options = this.options;
14538		var id = this.id = options.id || this.instance;
14539		var container = document.id(options.container);
14540
14541		Swiff.CallBacks[this.instance] = {};
14542
14543		var params = options.params, vars = options.vars, callBacks = options.callBacks;
14544		var properties = Object.append({height: options.height, width: options.width}, options.properties);
14545
14546		var self = this;
14547
14548		for (var callBack in callBacks){
14549			Swiff.CallBacks[this.instance][callBack] = (function(option){
14550				return function(){
14551					return option.apply(self.object, arguments);
14552				};
14553			})(callBacks[callBack]);
14554			vars[callBack] = 'Swiff.CallBacks.' + this.instance + '.' + callBack;
14555		}
14556
14557		params.flashVars = Object.toQueryString(vars);
14558		if ('ActiveXObject' in window){
14559			properties.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
14560			params.movie = path;
14561		} else {
14562			properties.type = 'application/x-shockwave-flash';
14563		}
14564		properties.data = path;
14565
14566		var build = '<object id="' + id + '"';
14567		for (var property in properties) build += ' ' + property + '="' + properties[property] + '"';
14568		build += '>';
14569		for (var param in params){
14570			if (params[param]) build += '<param name="' + param + '" value="' + params[param] + '" />';
14571		}
14572		build += '</object>';
14573		this.object = ((container) ? container.empty() : new Element('div')).set('html', build).firstChild;
14574	},
14575
14576	replaces: function(element){
14577		element = document.id(element, true);
14578		element.parentNode.replaceChild(this.toElement(), element);
14579		return this;
14580	},
14581
14582	inject: function(element){
14583		document.id(element, true).appendChild(this.toElement());
14584		return this;
14585	},
14586
14587	remote: function(){
14588		return Swiff.remote.apply(Swiff, [this.toElement()].append(arguments));
14589	}
14590
14591});
14592
14593Swiff.CallBacks = {};
14594
14595Swiff.remote = function(obj, fn){
14596	var rs = obj.CallFunction('<invoke name="' + fn + '" returntype="javascript">' + __flash__argumentsToXML(arguments, 2) + '</invoke>');
14597	return eval(rs);
14598};
14599
14600})();
14601
14602/*
14603---
14604name: Table
14605description: LUA-Style table implementation.
14606license: MIT-style license
14607authors:
14608  - Valerio Proietti
14609requires: [Core/Array]
14610provides: [Table]
14611...
14612*/
14613
14614(function(){
14615
14616var Table = this.Table = function(){
14617
14618	this.length = 0;
14619	var keys = [],
14620		values = [];
14621
14622	this.set = function(key, value){
14623		var index = keys.indexOf(key);
14624		if (index == -1){
14625			var length = keys.length;
14626			keys[length] = key;
14627			values[length] = value;
14628			this.length++;
14629		} else {
14630			values[index] = value;
14631		}
14632		return this;
14633	};
14634
14635	this.get = function(key){
14636		var index = keys.indexOf(key);
14637		return (index == -1) ? null : values[index];
14638	};
14639
14640	this.erase = function(key){
14641		var index = keys.indexOf(key);
14642		if (index != -1){
14643			this.length--;
14644			keys.splice(index, 1);
14645			return values.splice(index, 1)[0];
14646		}
14647		return null;
14648	};
14649
14650	this.each = this.forEach = function(fn, bind){
14651		for (var i = 0, l = this.length; i < l; i++) fn.call(bind, keys[i], values[i], this);
14652	};
14653
14654};
14655
14656if (this.Type) new Type('Table', Table);
14657
14658})();

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.