PageSourceSearch

https://ceta-ciemat.es/media/system/js/mootools-more-uncompressed.js?fca8d582f9fb15c0941de076c470410c

js ceta-ciemat.es collected 2026-10-02 11:39:34 UTC 348,863 bytes, 13,373 lines download raw bytes

1// MooTools: the javascript framework.
2// Load this file's selection again by visiting: http://mootools.net/more/065f2f092ece4e3b32bb5214464cf926 
3// Or build this file again with packager using: packager build More/More More/Events.Pseudos More/Class.Refactor More/Class.Binds More/Class.Occlude More/Chain.Wait More/Array.Extras More/Date More/Date.Extras More/Number.Format More/Object.Extras More/String.Extras More/String.QueryString More/URI More/URI.Relative More/Hash More/Hash.Extras More/Element.Forms More/Elements.From More/Element.Event.Pseudos More/Element.Event.Pseudos.Keys More/Element.Measure More/Element.Pin More/Element.Position More/Element.Shortcuts More/Form.Request More/Form.Request.Append More/Form.Validator More/Form.Validator.Inline More/Form.Validator.Extras More/OverText More/Fx.Elements More/Fx.Accordion More/Fx.Move More/Fx.Reveal More/Fx.Scroll More/Fx.Slide More/Fx.SmoothScroll More/Fx.Sort More/Drag More/Drag.Move More/Slider More/Sortables More/Request.JSONP More/Request.Queue More/Request.Periodical More/Assets More/Color More/Group More/Hash.Cookie More/IframeShim More/Table More/HtmlTable More/HtmlTable.Zebra More/HtmlTable.Sort More/HtmlTable.Select More/Keyboard More/Keyboard.Extras More/Mask More/Scroller More/Tips More/Spinner More/Locale More/Locale.Set.From More/Locale.en-US.Date More/Locale.en-US.Form.Validator More/Locale.en-US.Number More/Locale.ar.Date More/Locale.ar.Form.Validator More/Locale.ca-CA.Date More/Locale.ca-CA.Form.Validator More/Locale.cs-CZ.Date More/Locale.cs-CZ.Form.Validator More/Locale.da-DK.Date More/Locale.da-DK.Form.Validator More/Locale.de-CH.Date More/Locale.de-CH.Form.Validator More/Locale.de-DE.Date More/Locale.de-DE.Form.Validator More/Locale.de-DE.Number More/Locale.en-GB.Date More/Locale.es-AR.Date More/Locale.es-AR.Form.Validator More/Locale.es-ES.Date More/Locale.es-ES.Form.Validator More/Locale.et-EE.Date More/Locale.et-EE.Form.Validator More/Locale.EU.Number More/Locale.fa.Date More/Locale.fa.Form.Validator More/Locale.fi-FI.Date More/Locale.fi-FI.Form.Validator More/Locale.fi-FI.Number More/Locale.fr-FR.Date More/Locale.fr-FR.Form.Validator More/Locale.fr-FR.Number More/Locale.he-IL.Date More/Locale.he-IL.Form.Validator More/Locale.he-IL.Number More/Locale.hu-HU.Date More/Locale.hu-HU.Form.Validator More/Locale.it-IT.Date More/Locale.it-IT.Form.Validator More/Locale.ja-JP.Date More/Locale.ja-JP.Form.Validator More/Locale.ja-JP.Number More/Locale.nl-NL.Date More/Locale.nl-NL.Form.Validator More/Locale.nl-NL.Number More/Locale.no-NO.Date More/Locale.no-NO.Form.Validator More/Locale.pl-PL.Date More/Locale.pl-PL.Form.Validator More/Locale.pt-BR.Date More/Locale.pt-BR.Form.Validator More/Locale.pt-PT.Date More/Locale.pt-PT.Form.Validator More/Locale.ru-RU-unicode.Date More/Locale.ru-RU-unicode.Form.Validator More/Locale.si-SI.Date More/Locale.si-SI.Form.Validator More/Locale.sv-SE.Date More/Locale.sv-SE.Form.Validator More/Locale.uk-UA.Date More/Locale.uk-UA.Form.Validator More/Locale.zh-CH.Date More/Locale.zh-CH.Form.Validator
4/*
5---
6
7script: More.js
8
9name: More
10
11description: MooTools More
12
13license: MIT-style license
14
15authors:
16  - Guillermo Rauch
17  - Thomas Aylott
18  - Scott Kyle
19  - Arian Stolwijk
20  - Tim Wienk
21  - Christoph Pojer
22  - Aaron Newton
23  - Jacob Thornton
24
25requires:
26  - Core/MooTools
27
28provides: [MooTools.More]
29
30...
31*/
32
33MooTools.More = {
34	'version': '1.4.0.1',
35	'build': 'a4244edf2aa97ac8a196fc96082dd35af1abab87'
36};
37
38
39/*
40---
41
42name: Events.Pseudos
43
44description: Adds the functionality to add pseudo events
45
46license: MIT-style license
47
48authors:
49  - Arian Stolwijk
50
51requires: [Core/Class.Extras, Core/Slick.Parser, More/MooTools.More]
52
53provides: [Events.Pseudos]
54
55...
56*/
57
58(function(){
59
60Events.Pseudos = function(pseudos, addEvent, removeEvent){
61
62	var storeKey = '_monitorEvents:';
63
64	var storageOf = function(object){
65		return {
66			store: object.store ? function(key, value){
67				object.store(storeKey + key, value);
68			} : function(key, value){
69				(object._monitorEvents || (object._monitorEvents = {}))[key] = value;
70			},
71			retrieve: object.retrieve ? function(key, dflt){
72				return object.retrieve(storeKey + key, dflt);
73			} : function(key, dflt){
74				if (!object._monitorEvents) return dflt;
75				return object._monitorEvents[key] || dflt;
76			}
77		};
78	};
79
80	var splitType = function(type){
81		if (type.indexOf(':') == -1 || !pseudos) return null;
82
83		var parsed = Slick.parse(type).expressions[0][0],
84			parsedPseudos = parsed.pseudos,
85			l = parsedPseudos.length,
86			splits = [];
87
88		while (l--){
89			var pseudo = parsedPseudos[l].key,
90				listener = pseudos[pseudo];
91			if (listener != null) splits.push({
92				event: parsed.tag,
93				value: parsedPseudos[l].value,
94				pseudo: pseudo,
95				original: type,
96				listener: listener
97			});
98		}
99		return splits.length ? splits : null;
100	};
101
102	return {
103
104		addEvent: function(type, fn, internal){
105			var split = splitType(type);
106			if (!split) return addEvent.call(this, type, fn, internal);
107
108			var storage = storageOf(this),
109				events = storage.retrieve(type, []),
110				eventType = split[0].event,
111				args = Array.slice(arguments, 2),
112				stack = fn,
113				self = this;
114
115			split.each(function(item){
116				var listener = item.listener,
117					stackFn = stack;
118				if (listener == false) eventType += ':' + item.pseudo + '(' + item.value + ')';
119				else stack = function(){
120					listener.call(self, item, stackFn, arguments, stack);
121				};
122			});
123
124			events.include({type: eventType, event: fn, monitor: stack});
125			storage.store(type, events);
126
127			if (type != eventType) addEvent.apply(this, [type, fn].concat(args));
128			return addEvent.apply(this, [eventType, stack].concat(args));
129		},
130
131		removeEvent: function(type, fn){
132			var split = splitType(type);
133			if (!split) return removeEvent.call(this, type, fn);
134
135			var storage = storageOf(this),
136				events = storage.retrieve(type);
137			if (!events) return this;
138
139			var args = Array.slice(arguments, 2);
140
141			removeEvent.apply(this, [type, fn].concat(args));
142			events.each(function(monitor, i){
143				if (!fn || monitor.event == fn) removeEvent.apply(this, [monitor.type, monitor.monitor].concat(args));
144				delete events[i];
145			}, this);
146
147			storage.store(type, events);
148			return this;
149		}
150
151	};
152
153};
154
155var pseudos = {
156
157	once: function(split, fn, args, monitor){
158		fn.apply(this, args);
159		this.removeEvent(split.event, monitor)
160			.removeEvent(split.original, fn);
161	},
162
163	throttle: function(split, fn, args){
164		if (!fn._throttled){
165			fn.apply(this, args);
166			fn._throttled = setTimeout(function(){
167				fn._throttled = false;
168			}, split.value || 250);
169		}
170	},
171
172	pause: function(split, fn, args){
173		clearTimeout(fn._pause);
174		fn._pause = fn.delay(split.value || 250, this, args);
175	}
176
177};
178
179Events.definePseudo = function(key, listener){
180	pseudos[key] = listener;
181	return this;
182};
183
184Events.lookupPseudo = function(key){
185	return pseudos[key];
186};
187
188var proto = Events.prototype;
189Events.implement(Events.Pseudos(pseudos, proto.addEvent, proto.removeEvent));
190
191['Request', 'Fx'].each(function(klass){
192	if (this[klass]) this[klass].implement(Events.prototype);
193});
194
195})();
196
197
198/*
199---
200
201script: Class.Refactor.js
202
203name: Class.Refactor
204
205description: Extends a class onto itself with new property, preserving any items attached to the class's namespace.
206
207license: MIT-style license
208
209authors:
210  - Aaron Newton
211
212requires:
213  - Core/Class
214  - /MooTools.More
215
216# Some modules declare themselves dependent on Class.Refactor
217provides: [Class.refactor, Class.Refactor]
218
219...
220*/
221
222Class.refactor = function(original, refactors){
223
224	Object.each(refactors, function(item, name){
225		var origin = original.prototype[name];
226		origin = (origin && origin.$origin) || origin || function(){};
227		original.implement(name, (typeof item == 'function') ? function(){
228			var old = this.previous;
229			this.previous = origin;
230			var value = item.apply(this, arguments);
231			this.previous = old;
232			return value;
233		} : item);
234	});
235
236	return original;
237
238};
239
240
241/*
242---
243
244script: Class.Binds.js
245
246name: Class.Binds
247
248description: Automagically binds specified methods in a class to the instance of the class.
249
250license: MIT-style license
251
252authors:
253  - Aaron Newton
254
255requires:
256  - Core/Class
257  - /MooTools.More
258
259provides: [Class.Binds]
260
261...
262*/
263
264Class.Mutators.Binds = function(binds){
265	if (!this.prototype.initialize) this.implement('initialize', function(){});
266	return Array.from(binds).concat(this.prototype.Binds || []);
267};
268
269Class.Mutators.initialize = function(initialize){
270	return function(){
271		Array.from(this.Binds).each(function(name){
272			var original = this[name];
273			if (original) this[name] = original.bind(this);
274		}, this);
275		return initialize.apply(this, arguments);
276	};
277};
278
279
280/*
281---
282
283script: Class.Occlude.js
284
285name: Class.Occlude
286
287description: Prevents a class from being applied to a DOM element twice.
288
289license: MIT-style license.
290
291authors:
292  - Aaron Newton
293
294requires:
295  - Core/Class
296  - Core/Element
297  - /MooTools.More
298
299provides: [Class.Occlude]
300
301...
302*/
303
304Class.Occlude = new Class({
305
306	occlude: function(property, element){
307		element = document.id(element || this.element);
308		var instance = element.retrieve(property || this.property);
309		if (instance && !this.occluded)
310			return (this.occluded = instance);
311
312		this.occluded = false;
313		element.store(property || this.property, this);
314		return this.occluded;
315	}
316
317});
318
319
320/*
321---
322
323script: Chain.Wait.js
324
325name: Chain.Wait
326
327description: value, Adds a method to inject pauses between chained events.
328
329license: MIT-style license.
330
331authors:
332  - Aaron Newton
333
334requires:
335  - Core/Chain
336  - Core/Element
337  - Core/Fx
338  - /MooTools.More
339
340provides: [Chain.Wait]
341
342...
343*/
344
345(function(){
346
347	var wait = {
348		wait: function(duration){
349			return this.chain(function(){
350				this.callChain.delay(duration == null ? 500 : duration, this);
351				return this;
352			}.bind(this));
353		}
354	};
355
356	Chain.implement(wait);
357
358	if (this.Fx) Fx.implement(wait);
359
360	if (this.Element && Element.implement && this.Fx){
361		Element.implement({
362
363			chains: function(effects){
364				Array.from(effects || ['tween', 'morph', 'reveal']).each(function(effect){
365					effect = this.get(effect);
366					if (!effect) return;
367					effect.setOptions({
368						link:'chain'
369					});
370				}, this);
371				return this;
372			},
373
374			pauseFx: function(duration, effect){
375				this.chains(effect).get(effect || 'tween').wait(duration);
376				return this;
377			}
378
379		});
380	}
381
382})();
383
384
385/*
386---
387
388script: Array.Extras.js
389
390name: Array.Extras
391
392description: Extends the Array native object to include useful methods to work with arrays.
393
394license: MIT-style license
395
396authors:
397  - Christoph Pojer
398  - Sebastian Markbåge
399
400requires:
401  - Core/Array
402  - MooTools.More
403
404provides: [Array.Extras]
405
406...
407*/
408
409(function(nil){
410
411Array.implement({
412
413	min: function(){
414		return Math.min.apply(null, this);
415	},
416
417	max: function(){
418		return Math.max.apply(null, this);
419	},
420
421	average: function(){
422		return this.length ? this.sum() / this.length : 0;
423	},
424
425	sum: function(){
426		var result = 0, l = this.length;
427		if (l){
428			while (l--) result += this[l];
429		}
430		return result;
431	},
432
433	unique: function(){
434		return [].combine(this);
435	},
436
437	shuffle: function(){
438		for (var i = this.length; i && --i;){
439			var temp = this[i], r = Math.floor(Math.random() * ( i + 1 ));
440			this[i] = this[r];
441			this[r] = temp;
442		}
443		return this;
444	},
445
446	reduce: function(fn, value){
447		for (var i = 0, l = this.length; i < l; i++){
448			if (i in this) value = value === nil ? this[i] : fn.call(null, value, this[i], i, this);
449		}
450		return value;
451	},
452
453	reduceRight: function(fn, value){
454		var i = this.length;
455		while (i--){
456			if (i in this) value = value === nil ? this[i] : fn.call(null, value, this[i], i, this);
457		}
458		return value;
459	}
460
461});
462
463})();
464
465
466/*
467---
468
469script: Object.Extras.js
470
471name: Object.Extras
472
473description: Extra Object generics, like getFromPath which allows a path notation to child elements.
474
475license: MIT-style license
476
477authors:
478  - Aaron Newton
479
480requires:
481  - Core/Object
482  - /MooTools.More
483
484provides: [Object.Extras]
485
486...
487*/
488
489(function(){
490
491var defined = function(value){
492	return value != null;
493};
494
495var hasOwnProperty = Object.prototype.hasOwnProperty;
496
497Object.extend({
498
499	getFromPath: function(source, parts){
500		if (typeof parts == 'string') parts = parts.split('.');
501		for (var i = 0, l = parts.length; i < l; i++){
502			if (hasOwnProperty.call(source, parts[i])) source = source[parts[i]];
503			else return null;
504		}
505		return source;
506	},
507
508	cleanValues: function(object, method){
509		method = method || defined;
510		for (var key in object) if (!method(object[key])){
511			delete object[key];
512		}
513		return object;
514	},
515
516	erase: function(object, key){
517		if (hasOwnProperty.call(object, key)) delete object[key];
518		return object;
519	},
520
521	run: function(object){
522		var args = Array.slice(arguments, 1);
523		for (var key in object) if (object[key].apply){
524			object[key].apply(object, args);
525		}
526		return object;
527	}
528
529});
530
531})();
532
533
534/*
535---
536
537script: Locale.js
538
539name: Locale
540
541description: Provides methods for localization.
542
543license: MIT-style license
544
545authors:
546  - Aaron Newton
547  - Arian Stolwijk
548
549requires:
550  - Core/Events
551  - /Object.Extras
552  - /MooTools.More
553
554provides: [Locale, Lang]
555
556...
557*/
558
559(function(){
560
561var current = null,
562	locales = {},
563	inherits = {};
564
565var getSet = function(set){
566	if (instanceOf(set, Locale.Set)) return set;
567	else return locales[set];
568};
569
570var Locale = this.Locale = {
571
572	define: function(locale, set, key, value){
573		var name;
574		if (instanceOf(locale, Locale.Set)){
575			name = locale.name;
576			if (name) locales[name] = locale;
577		} else {
578			name = locale;
579			if (!locales[name]) locales[name] = new Locale.Set(name);
580			locale = locales[name];
581		}
582
583		if (set) locale.define(set, key, value);
584
585		
586
587		if (!current) current = locale;
588
589		return locale;
590	},
591
592	use: function(locale){
593		locale = getSet(locale);
594
595		if (locale){
596			current = locale;
597
598			this.fireEvent('change', locale);
599
600			
601		}
602
603		return this;
604	},
605
606	getCurrent: function(){
607		return current;
608	},
609
610	get: function(key, args){
611		return (current) ? current.get(key, args) : '';
612	},
613
614	inherit: function(locale, inherits, set){
615		locale = getSet(locale);
616
617		if (locale) locale.inherit(inherits, set);
618		return this;
619	},
620
621	list: function(){
622		return Object.keys(locales);
623	}
624
625};
626
627Object.append(Locale, new Events);
628
629Locale.Set = new Class({
630
631	sets: {},
632
633	inherits: {
634		locales: [],
635		sets: {}
636	},
637
638	initialize: function(name){
639		this.name = name || '';
640	},
641
642	define: function(set, key, value){
643		var defineData = this.sets[set];
644		if (!defineData) defineData = {};
645
646		if (key){
647			if (typeOf(key) == 'object') defineData = Object.merge(defineData, key);
648			else defineData[key] = value;
649		}
650		this.sets[set] = defineData;
651
652		return this;
653	},
654
655	get: function(key, args, _base){
656		var value = Object.getFromPath(this.sets, key);
657		if (value != null){
658			var type = typeOf(value);
659			if (type == 'function') value = value.apply(null, Array.from(args));
660			else if (type == 'object') value = Object.clone(value);
661			return value;
662		}
663
664		// get value of inherited locales
665		var index = key.indexOf('.'),
666			set = index < 0 ? key : key.substr(0, index),
667			names = (this.inherits.sets[set] || []).combine(this.inherits.locales).include('en-US');
668		if (!_base) _base = [];
669
670		for (var i = 0, l = names.length; i < l; i++){
671			if (_base.contains(names[i])) continue;
672			_base.include(names[i]);
673
674			var locale = locales[names[i]];
675			if (!locale) continue;
676
677			value = locale.get(key, args, _base);
678			if (value != null) return value;
679		}
680
681		return '';
682	},
683
684	inherit: function(names, set){
685		names = Array.from(names);
686
687		if (set && !this.inherits.sets[set]) this.inherits.sets[set] = [];
688
689		var l = names.length;
690		while (l--) (set ? this.inherits.sets[set] : this.inherits.locales).unshift(names[l]);
691
692		return this;
693	}
694
695});
696
697
698
699})();
700
701
702/*
703---
704
705name: Locale.en-US.Date
706
707description: Date messages for US English.
708
709license: MIT-style license
710
711authors:
712  - Aaron Newton
713
714requires:
715  - /Locale
716
717provides: [Locale.en-US.Date]
718
719...
720*/
721
722Locale.define('en-US', 'Date', {
723
724	months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
725	months_abbr: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
726	days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
727	days_abbr: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
728
729	// Culture's date order: MM/DD/YYYY
730	dateOrder: ['month', 'date', 'year'],
731	shortDate: '%m/%d/%Y',
732	shortTime: '%I:%M%p',
733	AM: 'AM',
734	PM: 'PM',
735	firstDayOfWeek: 0,
736
737	// Date.Extras
738	ordinal: function(dayOfMonth){
739		// 1st, 2nd, 3rd, etc.
740		return (dayOfMonth > 3 && dayOfMonth < 21) ? 'th' : ['th', 'st', 'nd', 'rd', 'th'][Math.min(dayOfMonth % 10, 4)];
741	},
742
743	lessThanMinuteAgo: 'less than a minute ago',
744	minuteAgo: 'about a minute ago',
745	minutesAgo: '{delta} minutes ago',
746	hourAgo: 'about an hour ago',
747	hoursAgo: 'about {delta} hours ago',
748	dayAgo: '1 day ago',
749	daysAgo: '{delta} days ago',
750	weekAgo: '1 week ago',
751	weeksAgo: '{delta} weeks ago',
752	monthAgo: '1 month ago',
753	monthsAgo: '{delta} months ago',
754	yearAgo: '1 year ago',
755	yearsAgo: '{delta} years ago',
756
757	lessThanMinuteUntil: 'less than a minute from now',
758	minuteUntil: 'about a minute from now',
759	minutesUntil: '{delta} minutes from now',
760	hourUntil: 'about an hour from now',
761	hoursUntil: 'about {delta} hours from now',
762	dayUntil: '1 day from now',
763	daysUntil: '{delta} days from now',
764	weekUntil: '1 week from now',
765	weeksUntil: '{delta} weeks from now',
766	monthUntil: '1 month from now',
767	monthsUntil: '{delta} months from now',
768	yearUntil: '1 year from now',
769	yearsUntil: '{delta} years from now'
770
771});
772
773
774/*
775---
776
777script: Date.js
778
779name: Date
780
781description: Extends the Date native object to include methods useful in managing dates.
782
783license: MIT-style license
784
785authors:
786  - Aaron Newton
787  - Nicholas Barthelemy - https://svn.nbarthelemy.com/date-js/
788  - Harald Kirshner - mail [at] digitarald.de; http://digitarald.de
789  - Scott Kyle - scott [at] appden.com; http://appden.com
790
791requires:
792  - Core/Array
793  - Core/String
794  - Core/Number
795  - MooTools.More
796  - Locale
797  - Locale.en-US.Date
798
799provides: [Date]
800
801...
802*/
803
804(function(){
805
806var Date = this.Date;
807
808var DateMethods = Date.Methods = {
809	ms: 'Milliseconds',
810	year: 'FullYear',
811	min: 'Minutes',
812	mo: 'Month',
813	sec: 'Seconds',
814	hr: 'Hours'
815};
816
817['Date', 'Day', 'FullYear', 'Hours', 'Milliseconds', 'Minutes', 'Month', 'Seconds', 'Time', 'TimezoneOffset',
818	'Week', 'Timezone', 'GMTOffset', 'DayOfYear', 'LastMonth', 'LastDayOfMonth', 'UTCDate', 'UTCDay', 'UTCFullYear',
819	'AMPM', 'Ordinal', 'UTCHours', 'UTCMilliseconds', 'UTCMinutes', 'UTCMonth', 'UTCSeconds', 'UTCMilliseconds'].each(function(method){
820	Date.Methods[method.toLowerCase()] = method;
821});
822
823var pad = function(n, digits, string){
824	if (digits == 1) return n;
825	return n < Math.pow(10, digits - 1) ? (string || '0') + pad(n, digits - 1, string) : n;
826};
827
828Date.implement({
829
830	set: function(prop, value){
831		prop = prop.toLowerCase();
832		var method = DateMethods[prop] && 'set' + DateMethods[prop];
833		if (method && this[method]) this[method](value);
834		return this;
835	}.overloadSetter(),
836
837	get: function(prop){
838		prop = prop.toLowerCase();
839		var method = DateMethods[prop] && 'get' + DateMethods[prop];
840		if (method && this[method]) return this[method]();
841		return null;
842	}.overloadGetter(),
843
844	clone: function(){
845		return new Date(this.get('time'));
846	},
847
848	increment: function(interval, times){
849		interval = interval || 'day';
850		times = times != null ? times : 1;
851
852		switch (interval){
853			case 'year':
854				return this.increment('month', times * 12);
855			case 'month':
856				var d = this.get('date');
857				this.set('date', 1).set('mo', this.get('mo') + times);
858				return this.set('date', d.min(this.get('lastdayofmonth')));
859			case 'week':
860				return this.increment('day', times * 7);
861			case 'day':
862				return this.set('date', this.get('date') + times);
863		}
864
865		if (!Date.units[interval]) throw new Error(interval + ' is not a supported interval');
866
867		return this.set('time', this.get('time') + times * Date.units[interval]());
868	},
869
870	decrement: function(interval, times){
871		return this.increment(interval, -1 * (times != null ? times : 1));
872	},
873
874	isLeapYear: function(){
875		return Date.isLeapYear(this.get('year'));
876	},
877
878	clearTime: function(){
879		return this.set({hr: 0, min: 0, sec: 0, ms: 0});
880	},
881
882	diff: function(date, resolution){
883		if (typeOf(date) == 'string') date = Date.parse(date);
884
885		return ((date - this) / Date.units[resolution || 'day'](3, 3)).round(); // non-leap year, 30-day month
886	},
887
888	getLastDayOfMonth: function(){
889		return Date.daysInMonth(this.get('mo'), this.get('year'));
890	},
891
892	getDayOfYear: function(){
893		return (Date.UTC(this.get('year'), this.get('mo'), this.get('date') + 1)
894			- Date.UTC(this.get('year'), 0, 1)) / Date.units.day();
895	},
896
897	setDay: function(day, firstDayOfWeek){
898		if (firstDayOfWeek == null){
899			firstDayOfWeek = Date.getMsg('firstDayOfWeek');
900			if (firstDayOfWeek === '') firstDayOfWeek = 1;
901		}
902
903		day = (7 + Date.parseDay(day, true) - firstDayOfWeek) % 7;
904		var currentDay = (7 + this.get('day') - firstDayOfWeek) % 7;
905
906		return this.increment('day', day - currentDay);
907	},
908
909	getWeek: function(firstDayOfWeek){
910		if (firstDayOfWeek == null){
911			firstDayOfWeek = Date.getMsg('firstDayOfWeek');
912			if (firstDayOfWeek === '') firstDayOfWeek = 1;
913		}
914
915		var date = this,
916			dayOfWeek = (7 + date.get('day') - firstDayOfWeek) % 7,
917			dividend = 0,
918			firstDayOfYear;
919
920		if (firstDayOfWeek == 1){
921			// ISO-8601, week belongs to year that has the most days of the week (i.e. has the thursday of the week)
922			var month = date.get('month'),
923				startOfWeek = date.get('date') - dayOfWeek;
924
925			if (month == 11 && startOfWeek > 28) return 1; // Week 1 of next year
926
927			if (month == 0 && startOfWeek < -2){
928				// Use a date from last year to determine the week
929				date = new Date(date).decrement('day', dayOfWeek);
930				dayOfWeek = 0;
931			}
932
933			firstDayOfYear = new Date(date.get('year'), 0, 1).get('day') || 7;
934			if (firstDayOfYear > 4) dividend = -7; // First week of the year is not week 1
935		} else {
936			// In other cultures the first week of the year is always week 1 and the last week always 53 or 54.
937			// Days in the same week can have a different weeknumber if the week spreads across two years.
938			firstDayOfYear = new Date(date.get('year'), 0, 1).get('day');
939		}
940
941		dividend += date.get('dayofyear');
942		dividend += 6 - dayOfWeek; // Add days so we calculate the current date's week as a full week
943		dividend += (7 + firstDayOfYear - firstDayOfWeek) % 7; // Make up for first week of the year not being a full week
944
945		return (dividend / 7);
946	},
947
948	getOrdinal: function(day){
949		return Date.getMsg('ordinal', day || this.get('date'));
950	},
951
952	getTimezone: function(){
953		return this.toString()
954			.replace(/^.*? ([A-Z]{3}).[0-9]{4}.*$/, '$1')
955			.replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, '$1$2$3');
956	},
957
958	getGMTOffset: function(){
959		var off = this.get('timezoneOffset');
960		return ((off > 0) ? '-' : '+') + pad((off.abs() / 60).floor(), 2) + pad(off % 60, 2);
961	},
962
963	setAMPM: function(ampm){
964		ampm = ampm.toUpperCase();
965		var hr = this.get('hr');
966		if (hr >
966 11 && ampm == 'AM') return this.decrement('hour', 12);
967		else if (hr < 12 && ampm == 'PM') return this.increment('hour', 12);
968		return this;
969	},
970
971	getAMPM: function(){
972		return (this.get('hr') < 12) ? 'AM' : 'PM';
973	},
974
975	parse: function(str){
976		this.set('time', Date.parse(str));
977		return this;
978	},
979
980	isValid: function(date){
981		if (!date) date = this;
982		return typeOf(date) == 'date' && !isNaN(date.valueOf());
983	},
984
985	format: function(format){
986		if (!this.isValid()) return 'invalid date';
987
988		if (!format) format = '%x %X';
989		if (typeof format == 'string') format = formats[format.toLowerCase()] || format;
990		if (typeof format == 'function') return format(this);
991
992		var d = this;
993		return format.replace(/%([a-z%])/gi,
994			function($0, $1){
995				switch ($1){
996					case 'a': return Date.getMsg('days_abbr')[d.get('day')];
997					case 'A': return Date.getMsg('days')[d.get('day')];
998					case 'b': return Date.getMsg('months_abbr')[d.get('month')];
999					case 'B': return Date.getMsg('months')[d.get('month')];
1000					case 'c': return d.format('%a %b %d %H:%M:%S %Y');
1001					case 'd': return pad(d.get('date'), 2);
1002					case 'e': return pad(d.get('date'), 2, ' ');
1003					case 'H': return pad(d.get('hr'), 2);
1004					case 'I': return pad((d.get('hr') % 12) || 12, 2);
1005					case 'j': return pad(d.get('dayofyear'), 3);
1006					case 'k': return pad(d.get('hr'), 2, ' ');
1007					case 'l': return pad((d.get('hr') % 12) || 12, 2, ' ');
1008					case 'L': return pad(d.get('ms'), 3);
1009					case 'm': return pad((d.get('mo') + 1), 2);
1010					case 'M': return pad(d.get('min'), 2);
1011					case 'o': return d.get('ordinal');
1012					case 'p': return Date.getMsg(d.get('ampm'));
1013					case 's': return Math.round(d / 1000);
1014					case 'S': return pad(d.get('seconds'), 2);
1015					case 'T': return d.format('%H:%M:%S');
1016					case 'U': return pad(d.get('week'), 2);
1017					case 'w': return d.get('day');
1018					case 'x': return d.format(Date.getMsg('shortDate'));
1019					case 'X': return d.format(Date.getMsg('shortTime'));
1020					case 'y': return d.get('year').toString().substr(2);
1021					case 'Y': return d.get('year');
1022					case 'z': return d.get('GMTOffset');
1023					case 'Z': return d.get('Timezone');
1024				}
1025				return $1;
1026			}
1027		);
1028	},
1029
1030	toISOString: function(){
1031		return this.format('iso8601');
1032	}
1033
1034}).alias({
1035	toJSON: 'toISOString',
1036	compare: 'diff',
1037	strftime: 'format'
1038});
1039
1040// The day and month abbreviations are standardized, so we cannot use simply %a and %b because they will get localized
1041var rfcDayAbbr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
1042	rfcMonthAbbr = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
1043
1044var formats = {
1045	db: '%Y-%m-%d %H:%M:%S',
1046	compact: '%Y%m%dT%H%M%S',
1047	'short': '%d %b %H:%M',
1048	'long': '%B %d, %Y %H:%M',
1049	rfc822: function(date){
1050		return rfcDayAbbr[date.get('day')] + date.format(', %d ') + rfcMonthAbbr[date.get('month')] + date.format(' %Y %H:%M:%S %Z');
1051	},
1052	rfc2822: function(date){
1053		return rfcDayAbbr[date.get('day')] + date.format(', %d ') + rfcMonthAbbr[date.get('month')] + date.format(' %Y %H:%M:%S %z');
1054	},
1055	iso8601: function(date){
1056		return (
1057			date.getUTCFullYear() + '-' +
1058			pad(date.getUTCMonth() + 1, 2) + '-' +
1059			pad(date.getUTCDate(), 2) + 'T' +
1060			pad(date.getUTCHours(), 2) + ':' +
1061			pad(date.getUTCMinutes(), 2) + ':' +
1062			pad(date.getUTCSeconds(), 2) + '.' +
1063			pad(date.getUTCMilliseconds(), 3) + 'Z'
1064		);
1065	}
1066};
1067
1068var parsePatterns = [],
1069	nativeParse = Date.parse;
1070
1071var parseWord = function(type, word, num){
1072	var ret = -1,
1073		translated = Date.getMsg(type + 's');
1074	switch (typeOf(word)){
1075		case 'object':
1076			ret = translated[word.get(type)];
1077			break;
1078		case 'number':
1079			ret = translated[word];
1080			if (!ret) throw new Error('Invalid ' + type + ' index: ' + word);
1081			break;
1082		case 'string':
1083			var match = translated.filter(function(name){
1084				return this.test(name);
1085			}, new RegExp('^' + word, 'i'));
1086			if (!match.length) throw new Error('Invalid ' + type + ' string');
1087			if (match.length > 1) throw new Error('Ambiguous ' + type);
1088			ret = match[0];
1089	}
1090
1091	return (num) ? translated.indexOf(ret) : ret;
1092};
1093
1094var startCentury = 1900,
1095	startYear = 70;
1096
1097Date.extend({
1098
1099	getMsg: function(key, args){
1100		return Locale.get('Date.' + key, args);
1101	},
1102
1103	units: {
1104		ms: Function.from(1),
1105		second: Function.from(1000),
1106		minute: Function.from(60000),
1107		hour: Function.from(3600000),
1108		day: Function.from(86400000),
1109		week: Function.from(608400000),
1110		month: function(month, year){
1111			var d = new Date;
1112			return Date.daysInMonth(month != null ? month : d.get('mo'), year != null ? year : d.get('year')) * 86400000;
1113		},
1114		year: function(year){
1115			year = year || new Date().get('year');
1116			return Date.isLeapYear(year) ? 31622400000 : 31536000000;
1117		}
1118	},
1119
1120	daysInMonth: function(month, year){
1121		return [31, Date.isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
1122	},
1123
1124	isLeapYear: function(year){
1125		return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
1126	},
1127
1128	parse: function(from){
1129		var t = typeOf(from);
1130		if (t == 'number') return new Date(from);
1131		if (t != 'string') return from;
1132		from = from.clean();
1133		if (!from.length) return null;
1134
1135		var parsed;
1136		parsePatterns.some(function(pattern){
1137			var bits = pattern.re.exec(from);
1138			return (bits) ? (parsed = pattern.handler(bits)) : false;
1139		});
1140
1141		if (!(parsed && parsed.isValid())){
1142			parsed = new Date(nativeParse(from));
1143			if (!(parsed && parsed.isValid())) parsed = new Date(from.toInt());
1144		}
1145		return parsed;
1146	},
1147
1148	parseDay: function(day, num){
1149		return parseWord('day', day, num);
1150	},
1151
1152	parseMonth: function(month, num){
1153		return parseWord('month', month, num);
1154	},
1155
1156	parseUTC: function(value){
1157		var localDate = new Date(value);
1158		var utcSeconds = Date.UTC(
1159			localDate.get('year'),
1160			localDate.get('mo'),
1161			localDate.get('date'),
1162			localDate.get('hr'),
1163			localDate.get('min'),
1164			localDate.get('sec'),
1165			localDate.get('ms')
1166		);
1167		return new Date(utcSeconds);
1168	},
1169
1170	orderIndex: function(unit){
1171		return Date.getMsg('dateOrder').indexOf(unit) + 1;
1172	},
1173
1174	defineFormat: function(name, format){
1175		formats[name] = format;
1176		return this;
1177	},
1178
1179	
1180
1181	defineParser: function(pattern){
1182		parsePatterns.push((pattern.re && pattern.handler) ? pattern : build(pattern));
1183		return this;
1184	},
1185
1186	defineParsers: function(){
1187		Array.flatten(arguments).each(Date.defineParser);
1188		return this;
1189	},
1190
1191	define2DigitYearStart: function(year){
1192		startYear = year % 100;
1193		startCentury = year - startYear;
1194		return this;
1195	}
1196
1197}).extend({
1198	defineFormats: Date.defineFormat.overloadSetter()
1199});
1200
1201var regexOf = function(type){
1202	return new RegExp('(?:' + Date.getMsg(type).map(function(name){
1203		return name.substr(0, 3);
1204	}).join('|') + ')[a-z]*');
1205};
1206
1207var replacers = function(key){
1208	switch (key){
1209		case 'T':
1210			return '%H:%M:%S';
1211		case 'x': // iso8601 covers yyyy-mm-dd, so just check if month is first
1212			return ((Date.orderIndex('month') == 1) ? '%m[-./]%d' : '%d[-./]%m') + '([-./]%y)?';
1213		case 'X':
1214			return '%H([.:]%M)?([.:]%S([.:]%s)?)? ?%p? ?%z?';
1215	}
1216	return null;
1217};
1218
1219var keys = {
1220	d: /[0-2]?[0-9]|3[01]/,
1221	H: /[01]?[0-9]|2[0-3]/,
1222	I: /0?[1-9]|1[0-2]/,
1223	M: /[0-5]?\d/,
1224	s: /\d+/,
1225	o: /[a-z]*/,
1226	p: /[ap]\.?m\.?/,
1227	y: /\d{2}|\d{4}/,
1228	Y: /\d{4}/,
1229	z: /Z|[+-]\d{2}(?::?\d{2})?/
1230};
1231
1232keys.m = keys.I;
1233keys.S = keys.M;
1234
1235var currentLanguage;
1236
1237var recompile = function(language){
1238	currentLanguage = language;
1239
1240	keys.a = keys.A = regexOf('days');
1241	keys.b = keys.B = regexOf('months');
1242
1243	parsePatterns.each(function(pattern, i){
1244		if (pattern.format) parsePatterns[i] = build(pattern.format);
1245	});
1246};
1247
1248var build = function(format){
1249	if (!currentLanguage) return {format: format};
1250
1251	var parsed = [];
1252	var re = (format.source || format) // allow format to be regex
1253	 .replace(/%([a-z])/gi,
1254		function($0, $1){
1255			return replacers($1) || $0;
1256		}
1257	).replace(/\((?!\?)/g, '(?:') // make all groups non-capturing
1258	 .replace(/ (?!\?|\*)/g, ',? ') // be forgiving with spaces and commas
1259	 .replace(/%([a-z%])/gi,
1260		function($0, $1){
1261			var p = keys[$1];
1262			if (!p) return $1;
1263			parsed.push($1);
1264			return '(' + p.source + ')';
1265		}
1266	).replace(/\[a-z\]/gi, '[a-z\\u00c0-\\uffff;\&]'); // handle unicode words
1267
1268	return {
1269		format: format,
1270		re: new RegExp('^' + re + '$', 'i'),
1271		handler: function(bits){
1272			bits = bits.slice(1).associate(parsed);
1273			var date = new Date().clearTime(),
1274				year = bits.y || bits.Y;
1275
1276			if (year != null) handle.call(date, 'y', year); // need to start in the right year
1277			if ('d' in bits) handle.call(date, 'd', 1);
1278			if ('m' in bits || bits.b || bits.B) handle.call(date, 'm', 1);
1279
1280			for (var key in bits) handle.call(date, key, bits[key]);
1281			return date;
1282		}
1283	};
1284};
1285
1286var handle = function(key, value){
1287	if (!value) return this;
1288
1289	switch (key){
1290		case 'a': case 'A': return this.set('day', Date.parseDay(value, true));
1291		case 'b': case 'B': return this.set('mo', Date.parseMonth(value, true));
1292		case 'd': return this.set('date', value);
1293		case 'H': case 'I': return this.set('hr', value);
1294		case 'm': return this.set('mo', value - 1);
1295		case 'M': return this.set('min', value);
1296		case 'p': return this.set('ampm', value.replace(/\./g, ''));
1297		case 'S': return this.set('sec', value);
1298		case 's': return this.set('ms', ('0.' + value) * 1000);
1299		case 'w': return this.set('day', value);
1300		case 'Y': return this.set('year', value);
1301		case 'y':
1302			value = +value;
1303			if (value < 100) value += startCentury + (value < startYear ? 100 : 0);
1304			return this.set('year', value);
1305		case 'z':
1306			if (value == 'Z') value = '+00';
1307			var offset = value.match(/([+-])(\d{2}):?(\d{2})?/);
1308			offset = (offset[1] + '1') * (offset[2] * 60 + (+offset[3] || 0)) + this.getTimezoneOffset();
1309			return this.set('time', this - offset * 60000);
1310	}
1311
1312	return this;
1313};
1314
1315Date.defineParsers(
1316	'%Y([-./]%m([-./]%d((T| )%X)?)?)?', // "1999-12-31", "1999-12-31 11:59pm", "1999-12-31 23:59:59", ISO8601
1317	'%Y%m%d(T%H(%M%S?)?)?', // "19991231", "19991231T1159", compact
1318	'%x( %X)?', // "12/31", "12.31.99", "12-31-1999", "12/31/2008 11:59 PM"
1319	'%d%o( %b( %Y)?)?( %X)?', // "31st", "31st December", "31 Dec 1999", "31 Dec 1999 11:59pm"
1320	'%b( %d%o)?( %Y)?( %X)?', // Same as above with month and day switched
1321	'%Y %b( %d%o( %X)?)?', // Same as above with year coming first
1322	'%o %b %d %X %z %Y', // "Thu Oct 22 08:11:23 +0000 2009"
1323	'%T', // %H:%M:%S
1324	'%H:%M( ?%p)?' // "11:05pm", "11:05 am" and "11:05"
1325);
1326
1327Locale.addEvent('change', function(language){
1328	if (Locale.get('Date')) recompile(language);
1329}).fireEvent('change', Locale.getCurrent());
1330
1331})();
1332
1333
1334/*
1335---
1336
1337script: Date.Extras.js
1338
1339name: Date.Extras
1340
1341description: Extends the Date native object to include extra methods (on to
1341p of those in Date.js).
1342
1343license: MIT-style license
1344
1345authors:
1346  - Aaron Newton
1347  - Scott Kyle
1348
1349requires:
1350  - /Date
1351
1352provides: [Date.Extras]
1353
1354...
1355*/
1356
1357Date.implement({
1358
1359	timeDiffInWords: function(to){
1360		return Date.distanceOfTimeInWords(this, to || new Date);
1361	},
1362
1363	timeDiff: function(to, separator){
1364		if (to == null) to = new Date;
1365		var delta = ((to - this) / 1000).floor().abs();
1366
1367		var vals = [],
1368			durations = [60, 60, 24, 365, 0],
1369			names = ['s', 'm', 'h', 'd', 'y'],
1370			value, duration;
1371
1372		for (var item = 0; item < durations.length; item++){
1373			if (item && !delta) break;
1374			value = delta;
1375			if ((duration = durations[item])){
1376				value = (delta % duration);
1377				delta = (delta / duration).floor();
1378			}
1379			vals.unshift(value + (names[item] || ''));
1380		}
1381
1382		return vals.join(separator || ':');
1383	}
1384
1385}).extend({
1386
1387	distanceOfTimeInWords: function(from, to){
1388		return Date.getTimePhrase(((to - from) / 1000).toInt());
1389	},
1390
1391	getTimePhrase: function(delta){
1392		var suffix = (delta < 0) ? 'Until' : 'Ago';
1393		if (delta < 0) delta *= -1;
1394
1395		var units = {
1396			minute: 60,
1397			hour: 60,
1398			day: 24,
1399			week: 7,
1400			month: 52 / 12,
1401			year: 12,
1402			eon: Infinity
1403		};
1404
1405		var msg = 'lessThanMinute';
1406
1407		for (var unit in units){
1408			var interval = units[unit];
1409			if (delta < 1.5 * interval){
1410				if (delta > 0.75 * interval) msg = unit;
1411				break;
1412			}
1413			delta /= interval;
1414			msg = unit + 's';
1415		}
1416
1417		delta = delta.round();
1418		return Date.getMsg(msg + suffix, delta).substitute({delta: delta});
1419	}
1420
1421}).defineParsers(
1422
1423	{
1424		// "today", "tomorrow", "yesterday"
1425		re: /^(?:tod|tom|yes)/i,
1426		handler: function(bits){
1427			var d = new Date().clearTime();
1428			switch (bits[0]){
1429				case 'tom': return d.increment();
1430				case 'yes': return d.decrement();
1431				default: return d;
1432			}
1433		}
1434	},
1435
1436	{
1437		// "next Wednesday", "last Thursday"
1438		re: /^(next|last) ([a-z]+)$/i,
1439		handler: function(bits){
1440			var d = new Date().clearTime();
1441			var day = d.getDay();
1442			var newDay = Date.parseDay(bits[2], true);
1443			var addDays = newDay - day;
1444			if (newDay <= day) addDays += 7;
1445			if (bits[1] == 'last') addDays -= 7;
1446			return d.set('date', d.getDate() + addDays);
1447		}
1448	}
1449
1450).alias('timeAgoInWords', 'timeDiffInWords');
1451
1452
1453/*
1454---
1455
1456name: Locale.en-US.Number
1457
1458description: Number messages for US English.
1459
1460license: MIT-style license
1461
1462authors:
1463  - Arian Stolwijk
1464
1465requires:
1466  - /Locale
1467
1468provides: [Locale.en-US.Number]
1469
1470...
1471*/
1472
1473Locale.define('en-US', 'Number', {
1474
1475	decimal: '.',
1476	group: ',',
1477
1478/* 	Commented properties are the defaults for Number.format
1479	decimals: 0,
1480	precision: 0,
1481	scientific: null,
1482
1483	prefix: null,
1484	suffic: null,
1485
1486	// Negative/Currency/percentage will mixin Number
1487	negative: {
1488		prefix: '-'
1489	},*/
1490
1491	currency: {
1492//		decimals: 2,
1493		prefix: '$ '
1494	}/*,
1495
1496	percentage: {
1497		decimals: 2,
1498		suffix: '%'
1499	}*/
1500
1501});
1502
1503
1504
1505
1506/*
1507---
1508name: Number.Format
1509description: Extends the Number Type object to include a number formatting method.
1510license: MIT-style license
1511authors: [Arian Stolwijk]
1512requires: [Core/Number, Locale.en-US.Number]
1513# Number.Extras is for compatibility
1514provides: [Number.Format, Number.Extras]
1515...
1516*/
1517
1518
1519Number.implement({
1520
1521	format: function(options){
1522		// Thanks dojo and YUI for some inspiration
1523		var value = this;
1524		options = options ? Object.clone(options) : {};
1525		var getOption = function(key){
1526			if (options[key] != null) return options[key];
1527			return Locale.get('Number.' + key);
1528		};
1529
1530		var negative = value < 0,
1531			decimal = getOption('decimal'),
1532			precision = getOption('precision'),
1533			group = getOption('group'),
1534			decimals = getOption('decimals');
1535
1536		if (negative){
1537			var negativeLocale = getOption('negative') || {};
1538			if (negativeLocale.prefix == null && negativeLocale.suffix == null) negativeLocale.prefix = '-';
1539			['prefix', 'suffix'].each(function(key){
1540				if (negativeLocale[key]) options[key] = getOption(key) + negativeLocale[key];
1541			});
1542
1543			value = -value;
1544		}
1545
1546		var prefix = getOption('prefix'),
1547			suffix = getOption('suffix');
1548
1549		if (decimals !== '' && decimals >= 0 && decimals <= 20) value = value.toFixed(decimals);
1550		if (precision >= 1 && precision <= 21) value = (+value).toPrecision(precision);
1551
1552		value += '';
1553		var index;
1554		if (getOption('scientific') === false && value.indexOf('e') > -1){
1555			var match = value.split('e'),
1556				zeros = +match[1];
1557			value = match[0].replace('.', '');
1558
1559			if (zeros < 0){
1560				zeros = -zeros - 1;
1561				index = match[0].indexOf('.');
1562				if (index > -1) zeros -= index - 1;
1563				while (zeros--) value = '0' + value;
1564				value = '0.' + value;
1565			} else {
1566				index = match[0].lastIndexOf('.');
1567				if (index > -1) zeros -= match[0].length - index - 1;
1568				while (zeros--) value += '0';
1569			}
1570		}
1571
1572		if (decimal != '.') value = value.replace('.', decimal);
1573
1574		if (group){
1575			index = value.lastIndexOf(decimal);
1576			index = (index > -1) ? index : value.length;
1577			var newOutput = value.substring(index),
1578				i = index;
1579
1580			while (i--){
1581				if ((index - i - 1) % 3 == 0 && i != (index - 1)) newOutput = group + newOutput;
1582				newOutput = value.charAt(i) + newOutput;
1583			}
1584
1585			value = newOutput;
1586		}
1587
1588		if (prefix) value = prefix + value;
1589		if (suffix) value += suffix;
1590
1591		return value;
1592	},
1593
1594	formatCurrency: function(decimals){
1595		var locale = Locale.get('Number.currency') || {};
1596		if (locale.scientific == null) locale.scientific = false;
1597		locale.decimals = decimals != null ? decimals
1598			: (locale.decimals == null ? 2 : locale.decimals);
1599
1600		return this.format(locale);
1601	},
1602
1603	formatPercentage: function(decimals){
1604		var locale = Locale.get('Number.percentage') || {};
1605		if (locale.suffix == null) locale.suffix = '%';
1606		locale.decimals = decimals != null ? decimals
1607			: (locale.decimals == null ? 2 : locale.decimals);
1608
1609		return this.format(locale);
1610	}
1611
1612});
1613
1614
1615/*
1616---
1617
1618script: String.Extras.js
1619
1620name: String.Extras
1621
1622description: Extends the String native object to include methods useful in managing various kinds of strings (query strings, urls, html, etc).
1623
1624license: MIT-style license
1625
1626authors:
1627  - Aaron Newton
1628  - Guillermo Rauch
1629  - Christopher Pitt
1630
1631requires:
1632  - Core/String
1633  - Core/Array
1634  - MooTools.More
1635
1636provides: [String.Extras]
1637
1638...
1639*/
1640
1641(function(){
1642
1643var special = {
1644	'a': /[àáâãäåăą]/g,
1645	'A': /[ÀÁÂÃÄÅĂĄ]/g,
1646	'c': /[ćčç]/g,
1647	'C': /[ĆČÇ]/g,
1648	'd': /[ďđ]/g,
1649	'D': /[ĎÐ]/g,
1650	'e': /[èéêëěę]/g,
1651	'E': /[ÈÉÊËĚĘ]/g,
1652	'g': /[ğ]/g,
1653	'G': /[Ğ]/g,
1654	'i': /[ìíîï]/g,
1655	'I': /[ÌÍÎÏ]/g,
1656	'l': /[ĺľł]/g,
1657	'L': /[ĹĽŁ]/g,
1658	'n': /[ñňń]/g,
1659	'N': /[ÑŇŃ]/g,
1660	'o': /[òóôõöøő]/g,
1661	'O': /[ÒÓÔÕÖØ]/g,
1662	'r': /[řŕ]/g,
1663	'R': /[ŘŔ]/g,
1664	's': /[ššş]/g,
1665	'S': /[ŠŞŚ]/g,
1666	't': /[ťţ]/g,
1667	'T': /[ŤŢ]/g,
1668	'ue': /[ü]/g,
1669	'UE': /[Ü]/g,
1670	'u': /[ùúûůµ]/g,
1671	'U': /[ÙÚÛŮ]/g,
1672	'y': /[ÿý]/g,
1673	'Y': /[ŸÝ]/g,
1674	'z': /[žźż]/g,
1675	'Z': /[ŽŹŻ]/g,
1676	'th': /[þ]/g,
1677	'TH': /[Þ]/g,
1678	'dh': /[ð]/g,
1679	'DH': /[Ð]/g,
1680	'ss': /[ß]/g,
1681	'oe': /[œ]/g,
1682	'OE': /[Œ]/g,
1683	'ae': /[æ]/g,
1684	'AE': /[Æ]/g
1685},
1686
1687tidy = {
1688	' ': /[\xa0\u2002\u2003\u2009]/g,
1689	'*': /[\xb7]/g,
1690	'\'': /[\u2018\u2019]/g,
1691	'"': /[\u201c\u201d]/g,
1692	'...': /[\u2026]/g,
1693	'-': /[\u2013]/g,
1694//	'--': /[\u2014]/g,
1695	'&raquo;': /[\uFFFD]/g
1696};
1697
1698var walk = function(string, replacements){
1699	var result = string, key;
1700	for (key in replacements) result = result.replace(replacements[key], key);
1701	return result;
1702};
1703
1704var getRegexForTag = function(tag, contents){
1705	tag = tag || '';
1706	var regstr = contents ? "<" + tag + "(?!\\w)[^>]*>([\\s\\S]*?)<\/" + tag + "(?!\\w)>" : "<\/?" + tag + "([^>]+)?>",
1707		reg = new RegExp(regstr, "gi");
1708	return reg;
1709};
1710
1711String.implement({
1712
1713	standardize: function(){
1714		return walk(this, special);
1715	},
1716
1717	repeat: function(times){
1718		return new Array(times + 1).join(this);
1719	},
1720
1721	pad: function(length, str, direction){
1722		if (this.length >= length) return this;
1723
1724		var pad = (str == null ? ' ' : '' + str)
1725			.repeat(length - this.length)
1726			.substr(0, length - this.length);
1727
1728		if (!direction || direction == 'right') return this + pad;
1729		if (direction == 'left') return pad + this;
1730
1731		return pad.substr(0, (pad.length / 2).floor()) + this + pad.substr(0, (pad.length / 2).ceil());
1732	},
1733
1734	getTags: function(tag, contents){
1735		return this.match(getRegexForTag(tag, contents)) || [];
1736	},
1737
1738	stripTags: function(tag, contents){
1739		return this.replace(getRegexForTag(tag, contents), '');
1740	},
1741
1742	tidy: function(){
1743		return walk(this, tidy);
1744	},
1745
1746	truncate: function(max, trail, atChar){
1747		var string = this;
1748		if (trail == null && arguments.length == 1) trail = '…';
1749		if (string.length > max){
1750			string = string.substring(0, max);
1751			if (atChar){
1752				var index = string.lastIndexOf(atChar);
1753				if (index != -1) string = string.substr(0, index);
1754			}
1755			if (trail) string += trail;
1756		}
1757		return string;
1758	}
1759
1760});
1761
1762})();
1763
1764
1765/*
1766---
1767
1768script: String.QueryString.js
1769
1770name: String.QueryString
1771
1772description: Methods for dealing with URI query strings.
1773
1774license: MIT-style license
1775
1776authors:
1777  - Sebastian Markbåge
1778  - Aaron Newton
1779  - Lennart Pilon
1780  - Valerio Proietti
1781
1782requires:
1783  - Core/Array
1784  - Core/String
1785  - /MooTools.More
1786
1787provides: [String.QueryString]
1788
1789...
1790*/
1791
1792String.implement({
1793
1794	parseQueryString: function(decodeKeys, decodeValues){
1795		if (decodeKeys == null) decodeKeys = true;
1796		if (decodeValues == null) decodeValues = true;
1797
1798		var vars = this.split(/[&;]/),
1799			object = {};
1800		if (!vars.length) return object;
1801
1802		vars.each(function(val){
1803			var index = val.indexOf('=') + 1,
1804				value = index ? val.substr(index) : '',
1805				keys = index ? val.substr(0, index - 1).match(/([^\]\[]+|(\B)(?=\]))/g) : [val],
1806				obj = object;
1807			if (!keys) return;
1808			if (decodeValues) value = decodeURIComponent(value);
1809			keys.each(function(key, i){
1810				if (decodeKeys) key = decodeURIComponent(key);
1811				var current = obj[key];
1812
1813				if (i < keys.length - 1) obj = obj[key] = current || {};
1814				else if (typeOf(current) == 'array') current.push(value);
1815				else obj[key] = current != null ? [current, value] : value;
1816			});
1817		});
1818
1819		return object;
1820	},
1821
1822	cleanQueryString: function(method){
1823		return this.split('&').filter(function(val){
1824			var index = val.indexOf('='),
1825				key = index < 0 ? '' : val.substr(0, index),
1826				value = val.substr(index + 1);
1827
1828			return method ? method.call(null, key, value) : (value || value === 0);
1829		}).join('&');
1830	}
1831
1832});
1833
1834
1835/*
1836---
1837
1838script: URI.js
1839
1840name: URI
1841
1842description: Provides methods useful in managing the window location and uris.
1843
1844license: MIT-style license
1845
1846authors:
1847  - Sebastian Markbåge
1848  - Aaron Newton
1849
1850requires:
1851  - Core/Object
1852  - Core/Class
1853  - Core/Class.Extras
1854  - Core/Element
1855  - /String.QueryString
1856
1857provides: [URI]
1858
1859...
1860*/
1861
1862(function(){
1863
1864var toString = function(){
1865	return this.get('value');
1866};
1867
1868var URI = this.URI = new Class({
1869
1870	Implements: Options,
1871
1872	options: {
1873		/*base: false*/
1874	},
1875
1876	regex: /^(?:(\w+):)?(?:\/\/(?:(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)?(\.\.?$|(?:[^?#\/]*\/)*)([^?#]*)(?:\?([^#]*))?(?:#(.*))?/,
1877	parts: ['scheme', 'user', 'password', 'host', 'port', 'directory', 'file', 'query', 'fragment'],
1878	schemes: {http: 80, https: 443, ftp: 21, rtsp: 554, mms: 1755, file: 0},
1879
1880	initialize: function(uri, options){
1881		this.setOptions(options);
1882		var base = this.options.base || URI.base;
1883		if (!uri) uri = base;
1884
1885		if (uri && uri.parsed) this.parsed = Object.clone(uri.parsed);
1886		else this.set('value', uri.href || uri.toString(), base ? new URI(base) : false);
1887	},
1888
1889	parse: function(value, base){
1890		var bits = value.match(this.regex);
1891		if (!bits) return false;
1892		bits.shift();
1893		return this.merge(bits.associate(this.parts), base);
1894	},
1895
1896	merge: function(bits, base){
1897		if ((!bits || !bits.scheme) && (!base || !base.scheme)) return false;
1898		if (base){
1899			this.parts.every(function(part){
1900				if (bits[part]) return false;
1901				bits[part] = base[part] || '';
1902				return true;
1903			});
1904		}
1905		bits.port = bits.port || this.schemes[bits.scheme.toLowerCase()];
1906		bits.directory = bits.directory ? this.parseDirectory(bits.directory, base ? base.directory : '') : '/';
1907		return bits;
1908	},
1909
1910	parseDirectory: function(directory, baseDirectory){
1911		directory = (directory.substr(0, 1) == '/' ? '' : (baseDirectory || '/')) + directory;
1912		if (!directory.test(URI.regs.directoryDot)) return directory;
1913		var result = [];
1914		directory.replace(URI.regs.endSlash, '').split('/').each(function(dir){
1915			if (dir == '..' && result.length > 0) result.pop();
1916			else if (dir != '.') result.push(dir);
1917		});
1918		return result.join('/') + '/';
1919	},
1920
1921	combine: function(bits){
1922		return bits.value || bits.scheme + '://' +
1923			(bits.user ? bits.user + (bits.password ? ':' + bits.password : '') + '@' : '') +
1924			(bits.host || '') + (bits.port && bits.port != this.schemes[bits.scheme] ? ':' + bits.port : '') +
1925			(bits.directory || '/') + (bits.file || '') +
1926			(bits.query ? '?' + bits.query : '') +
1927			(bits.fragment ? '#' + bits.fragment : '');
1928	},
1929
1930	set: function(part, value, base){
1931		if (part == 'value'){
1932			var scheme = value.match(URI.regs.scheme);
1933			if (scheme) scheme = scheme[1];
1934			if (scheme && this.schemes[scheme.toLowerCase()] == null) this.parsed = { scheme: scheme, value: value };
1935			else this.parsed = this.parse(value, (base || this).parsed) || (scheme ? { scheme: scheme, value: value } : { value: value });
1936		} else if (part == 'data'){
1937			this.setData(value);
1938		} else {
1939			this.parsed[part] = value;
1940		}
1941		return this;
1942	},
1943
1944	get: function(part, base){
1945		switch (part){
1946			case 'value': return this.combine(this.parsed, base ? base.parsed : false);
1947			case 'data' : return this.getData();
1948		}
1949		return this.parsed[part] || '';
1950	},
1951
1952	go: function(){
1953		document.location.href = this.toString();
1954	},
1955
1956	toURI: function(){
1957		return this;
1958	},
1959
1960	getData: function(key, part){
1961		var qs = this.get(part || 'query');
1962		if (!(qs || qs === 0)) return key ? null : {};
1963		var obj = qs.parseQueryString();
1964		return key ? obj[key] : obj;
1965	},
1966
1967	setData: function(values, merge, part){
1968		if (typeof values == 'string'){
1969			var data = this.getData();
1970			data[arguments[0]] = arguments[1];
1971			values = data;
1972		} else if (merge){
1973			values = Object.merge(this.getData(), values);
1974		}
1975		return this.set(part || 'query', Object.toQueryString(values));
1976	},
1977
1978	clearData: function(part){
1979		return this.set(part || 'query', '');
1980	},
1981
1982	toString: toString,
1983	valueOf: toString
1984
1985});
1986
1987URI.regs = {
1988	endSlash: /\/$/,
1989	scheme: /^(\w+):/,
1990	directoryDot: /\.\/|\.$/
1991};
1992
1993URI.base = new URI(Array.from(document.getElements('base[href]', true)).getLast(), {base: document.location});
1994
1995String.implement({
1996
1997	toURI: function(options){
1998		return new URI(this, options);
1999	}
2000
2001});
2002
2003})();
2004
2005
2006/*
2007---
2008
2009script: URI.Relative.js
2010
2011name: URI.Relative
2012
2013description: Extends the URI class to add methods for computing relative and absolute urls.
2014
2015license: MIT-style license
2016
2017authors:
2018  - Sebastian Markbåge
2019
2020
2021requires:
2022  - /Class.refactor
2023  - /URI
2024
2025provides: [URI.Relative]
2026
2027...
2028*/
2029
2030URI = Class.refactor(URI, {
2031
2032	combine: function(bits, base){
2033		if (!base || bits.scheme != base.scheme || bits.host != base.host || bits.port != base.port)
2034			return this.previous.apply(this, arguments);
2035		var end = bits.file + (bits.query ? '?' + bits.query : '') + (bits.fragment ? '#' + bits.fragment : '');
2036
2037		if (!base.directory) return (bits.directory || (bits.file ? '' : './')) + end;
2038
2039		var baseDir = base.directory.split('/'),
2040			relDir = bits.directory.split('/'),
2041			path = '',
2042			offset;
2043
2044		var i = 0;
2045		for (offset = 0; offset < baseDir.length && offset < relDir.length && baseDir[offset] == relDir[offset]; offset++);
2046		for (i = 0; i < baseDir.length - offset - 1; i++) path += '../';
2047		for (i = offset; i < relDir.length - 1; i++) path += relDir[i] + '/';
2048
2049		return (path || (bits.file ? '' : './')) + end;
2050	},
2051
2052	toAbsolute: function(base){
2053		base = new URI(base);
2054		if (base) base.set('directory', '').set('file', '');
2055		return this.toRelative(base);
2056	},
2057
2058	toRelative: function(base){
2059		return this.get('value', new URI(base));
2060	}
2061
2062});
2063
2064
2065/*
2066---
2067
2068name: Hash
2069
2070description: Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects.
2071
2072license: MIT-style license.
2073
2074requires:
2075  - Core/Object
2076  - /MooTools.More
2077
2078provides: [Hash]
2079
2080...
2081*/
2082
2083(function(){
2084
2085if (this.Hash) return;
2086
2087var Hash = this.Hash = new Type('Hash', function(object){
2088	if (typeOf(object) == 'hash') object = Object.clone(object.getClean());
2089	for (var key in object) this[key] = object[key];
2090	return this;
2091});
2092
2093this.$H = function(object){
2094	return new Hash(object);
2095};
2096
2097Hash.implement({
2098
2099	forEach: function(fn, bind){
2100		Object.forEach(this, fn, bind);
2101	},
2102
2103	getClean: function(){
2104		var clean = {};
2105		for (var key in this){
2106			if (this.hasOwnProperty(key)) clean[key] = this[key];
2107		}
2108		return clean;
2109	},
2110
2111	getLength: function(){
2112		var length = 0;
2113		for (var key in this){
2114			if (this.hasOwnProperty(key)) length++;
2115		}
2116		return length;
2117	}
2118
2119});
2120
2121Hash.alias('each', 'forEach');
2122
2123Hash.implement({
2124
2125	has: Object.prototype.hasOwnProperty,
2126
2127	keyOf: function(value){
2128		return Object.keyOf(this, value);
2129	},
2130
2131	hasValue: function(value){
2132		return Object.contains(this, value);
2133	},
2134
2135	extend: function(properties){
2136		Hash.each(properties || {}, function(value, key){
2137			Hash.set(this, key, value);
2138		}, this);
2139		return this;
2140	},
2141
2142	combine: function(properties){
2143		Hash.each(properties || {}, function(value, key){
2144			Hash.include(this, key, value);
2145		}, this);
2146		return this;
2147	},
2148
2149	erase: function(key){
2150		if (this.hasOwnProperty(key)) delete this[key];
2151		return this;
2152	},
2153
2154	get: function(key){
2155		return (this.hasOwnProperty(key)) ? this[key] : null;
2156	},
2157
2158	set: function(key, value){
2159		if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
2160		return this;
2161	},
2162
2163	empty: function(){
2164		Hash.each(this, function(value, key){
2165			delete this[key];
2166		}, this);
2167		return this;
2168	},
2169
2170	include: function(key, value){
2171		if (this[key] == undefined) this[key] = value;
2172		return this;
2173	},
2174
2175	map: function(fn, bind){
2176		return new Hash(Object.map(this, fn, bind));
2177	},
2178
2179	filter: function(fn, bind){
2180		return new Hash(Object.filter(this, fn, bind));
2181	},
2182
2183	every: function(fn, bind){
2184		return Object.every(this, fn, bind);
2185	},
2186
2187	some: function(fn, bind){
2188		return Object.some(this, fn, bind);
2189	},
2190
2191	getKeys: function(){
2192		return Object.keys(this);
2193	},
2194
2195	getValues: function(){
2196		return Object.values(this);
2197	},
2198
2199	toQueryString: function(base){
2200		return Object.toQueryString(this, base);
2201	}
2202
2203});
2204
2205Hash.alias({indexOf: 'keyOf', contains: 'hasValue'});
2206
2207
2208})();
2209
2210
2211
2212/*
2213---
2214
2215script: Hash.Extras.js
2216
2217name: Hash.Extras
2218
2219description: Extends the Hash Type to include getFromPath which allows a path notation to child elements.
2220
2221license: MIT-style license
2222
2223authors:
2224  - Aaron Newton
2225
2226requires:
2227  - /Hash
2228  - /Object.Extras
2229
2230provides: [Hash.Extras]
2231
2232...
2233*/
2234
2235Hash.implement({
2236
2237	getFromPath: function(notation){
2238		return Object.getFromPath(this, notation);
2239	},
2240
2241	cleanValues: function(method){
2242		return new Hash(Object.cleanValues(this, method));
2243	},
2244
2245	run: function(){
2246		Object.run(arguments);
2247	}
2248
2249});
2250
2251
2252/*
2253---
2254
2255script: Element.Forms.js
2256
2257name: Element.Forms
2258
2259description: Extends the Element native object to include methods useful in managing inputs.
2260
2261license: MIT-style license
2262
2263authors:
2264  - Aaron Newton
2265
2266requires:
2267  - Core/Element
2268  - /String.Extras
2269  - /MooTools.More
2270
2271provides: [Element.Forms]
2272
2273...
2274*/
2275
2276Element.implement({
2277
2278	tidy: function(){
2279		this.set('value', this.get('value').tidy());
2280	},
2281
2282	getTextInRange: function(start, end){
2283		return this.get('value').substring(start, end);
2284	},
2285
2286	getSelectedText: function(){
2287		if (this.setSelectionRange) return this.getTextInRange(this.getSelectionStart(), this.getSelectionEnd());
2288		return document.selection.createRange().text;
2289	},
2290
2291	getSelectedRange: function(){
2292		if (this.selectionStart != null){
2293			return {
2294				start: this.selectionStart,
2295				end: this.selectionEnd
2296			};
2297		}
2298
2299		var pos = {
2300			start: 0,
2301			end: 0
2302		};
2303		var range = this.getDocument().selection.createRange();
2304		if (!range || range.parentElement() != this) return pos;
2305		var duplicate = range.duplicate();
2306
2307		if (this.type == 'text'){
2308			pos.start = 0 - duplicate.moveStart('character', -100000);
2309			pos.end = pos.start + range.text.length;
2310		} else {
2311			var value = this.get('value');
2312			var offset = value.length;
2313			duplicate.moveToElementText(this);
2314			duplicate.setEndPoint('StartToEnd', range);
2315			if (duplicate.text.length) offset -= value.match(/[\n\r]*$/)[0].length;
2316			pos.end = offset - duplicate.text.length;
2317			duplicate.setEndPoint('StartToStart', range);
2318			pos.start = offset - duplicate.text.length;
2319		}
2320		return pos;
2321	},
2322
2323	getSelectionStart: function(){
2324		return this.getSelectedRange().start;
2325	},
2326
2327	getSelectionEnd: function(){
2328		return this.getSelectedRange().end;
2329	},
2330
2331	setCaretPosition: function(pos){
2332		if (pos == 'end') pos = this.get('value').length;
2333		this.selectRange(pos, pos);
2334		return this;
2335	},
2336
2337	getCaretPosition: function(){
2338		return this.getSelectedRange().start;
2339	},
2340
2341	selectRange: function(start, end){
2342		if (this.setSelectionRange){
2343			this.focus();
2344			this.setSelectionRange(start, end);
2345		} else {
2346			var value = this.get('value');
2347			var diff = value.substr(start, end - start).replace(/\r/g, '').length;
2348			start = value.substr(0, start).replace(/\r/g, '').length;
2349			var range = this.createTextRange();
2350			range.collapse(true);
2351			range.moveEnd('character', start + diff);
2352			range.moveStart('character', start);
2353			range.select();
2354		}
2355		return this;
2356	},
2357
2358	insertAtCursor: function(value, select){
2359		var pos = this.getSelectedRange();
2360		var text = this.get('value');
2361		this.set('value', text.substring(0, pos.start) + value + text.substring(pos.end, text.length));
2362		if (select !== false) this.selectRange(pos.start, pos.start + value.length);
2363		else this.setCaretPosition(pos.start + value.length);
2364		return this;
2365	},
2366
2367	insertAroundCursor: function(options, select){
2368		options = Object.append({
2369			before: '',
2370			defaultMiddle: '',
2371			after: ''
2372		}, options);
2373
2374		var value = this.getSelectedText() || options.defaultMiddle;
2375		var pos = this.getSelectedRange();
2376		var text = this.get('value');
2377
2378		if (pos.start == pos.end){
2379			this.set('value', text.substring(0, pos.start) + options.before + value + options.after + text.substring(pos.end, text.length));
2380			this.selectRange(pos.start + options.before.length, pos.end + options.before.length + value.length);
2381		} else {
2382			var current = text.substring(pos.start, pos.end);
2383			this.set('value', text.substring(0, pos.start) + options.before + current + options.after + text.substring(pos.end, text.length));
2384			var selStart = pos.start + options.before.length;
2385			if (select !== false) this.selectRange(selStart, selStart + current.length);
2386			else this.setCaretPosition(selStart + text.length);
2387		}
2388		return this;
2389	}
2390
2391});
2392
2393
2394/*
2395---
2396
2397script: Elements.From.js
2398
2399name: Elements.From
2400
2401description: Returns a collection of elements from a string of html.
2402
2403license: MIT-style license
2404
2405authors:
2406  - Aaron Newton
2407
2408requires:
2409  - Core/String
2410  - Core/Element
2411  - /MooTools.More
2412
2413provides: [Elements.from, Elements.From]
2414
2415...
2416*/
2417
2418Elements.from = function(text, excludeScripts){
2419	if (excludeScripts || excludeScripts == null) text = text.stripScripts();
2420
2421	var container, match = text.match(/^\s*<(t[dhr]|tbody|tfoot|thead)/i);
2422
2423	if (match){
2424		container = new Element('table');
2425		var tag = match[1].toLowerCase();
2426		if (['td', 'th', 'tr'].contains(tag)){
2427			container = new Element('tbody').inject(container);
2428			if (tag != 'tr') container = new Element('tr').inject(container);
2429		}
2430	}
2431
2432	return (container || new Element('div')).set('html', text).getChildren();
2433};
2434
2435
2436/*
2437---
2438
2439name: Element.Event.Pseudos
2440
2441description: Adds the functionality to add pseudo events for Elements
2442
2443license: MIT-style license
2444
2445authors:
2446  - Arian Stolwijk
2447
2448requires: [Core/Element.Event, Core/Element.Delegation, Events.Pseudos]
2449
2450provides: [Element.Event.Pseudos, Element.Delegation]
2451
2452...
2453*/
2454
2455(function(){
2456
2457var pseudos = {relay: false},
2458	copyFromEvents = ['once', 'throttle', 'pause'],
2459	count = copyFromEvents.length;
2460
2461while (count--) pseudos[copyFromEvents[count]] = Events.lookupPseudo(copyFromEvents[count]);
2462
2463DOMEvent.definePseudo = function(key, listener){
2464	pseudos[key] = listener;
2465	return this;
2466};
2467
2468var proto = Element.prototype;
2469[Element, Window, Document].invoke('implement', Events.Pseudos(pseudos, proto.addEvent, proto.removeEvent));
2470
2471})();
2472
2473
2474/*
2475---
2476
2477name: Element.Event.Pseudos.Keys
2478
2479description: Adds functionality fire events if certain keycombinations are pressed
2480
2481license: MIT-style license
2482
2483authors:
2484  - Arian Stolwijk
2485
2486requires: [Element.Event.Pseudos]
2487
2488provides: [Element.Event.Pseudos.Keys]
2489
2490...
2491*/
2492
2493(function(){
2494
2495var keysStoreKey = '$moo:keys-pressed',
2496	keysKeyupStoreKey = '$moo:keys-keyup';
2497
2498
2499DOMEvent.definePseudo('keys', function(split, fn, args){
2500
2501	var event = args[0],
2502		keys = [],
2503		pressed = this.retrieve(keysStoreKey, []);
2504
2505	keys.append(split.value.replace('++', function(){
2506		keys.push('+'); // shift++ and shift+++a
2507		return '';
2508	}).split('+'));
2509
2510	pressed.include(event.key);
2511
2512	if (keys.every(function(key){
2513		return pressed.contains(key);
2514	})) fn.apply(this, args);
2515
2516	this.store(keysStoreKey, pressed);
2517
2518	if (!this.retrieve(keysKeyupStoreKey)){
2519		var keyup = function(event){
2520			(function(){
2521				pressed = this.retrieve(keysStoreKey, []).erase(event.key);
2522				this.store(keysStoreKey, pressed);
2523			}).delay(0, this); // Fix for IE
2524		};
2525		this.store(keysKeyupStoreKey, keyup).addEvent('keyup', keyup);
2526	}
2527
2528});
2529
2530DOMEvent.defineKeys({
2531	'16': 'shift',
2532	'17': 'control',
2533	'18': 'alt',
2534	'20': 'capslock',
2535	'33': 'pageup',
2536	'34': 'pagedown',
2537	'35': 'end',
2538	'36': 'home',
2539	'144': 'numlock',
2540	'145': 'scrolllock',
2541	'186': ';',
2542	'187': '=',
2543	'188': ',',
2544	'190': '.',
2545	'191': '/',
2546	'192': '`',
2547	'219': '[',
2548	'220': '\\',
2549	'221': ']',
2550	'222': "'",
2551	'107': '+'
2552}).defineKey(Browser.firefox ? 109 : 189, '-');
2553
2554})();
2555
2556
2557/*
2558---
2559
2560script: Element.Measure.js
2561
2562name: Element.Measure
2563
2564description: Extends the Element native object to include methods useful in measuring dimensions.
2565
2566credits: "Element.measure / .expose methods by Daniel Steigerwald License: MIT-style license. Copyright: Copyright (c) 2008 Daniel Steigerwald, daniel.steigerwald.cz"
2567
2568license: MIT-style license
2569
2570authors:
2571  - Aaron Newton
2572
2573requires:
2574  - Core/Element.Style
2575  - Core/Element.Dimensions
2576  - /MooTools.More
2577
2578provides: [Element.Measure]
2579
2580...
2581*/
2582
2583(function(){
2584
2585var getStylesList = function(styles, planes){
2586	var list = [];
2587	Object.each(planes, function(directions){
2588		Object.each(directions, function(edge){
2589			styles.each(function(style){
2590				list.push(style + '-' + edge + (style == 'border' ? '-width' : ''));
2591			});
2592		});
2593	});
2594	return list;
2595};
2596
2597var calculateEdgeSize = function(edge, styles){
2598	var total = 0;
2599	Object.each(styles, function(value, style){
2600		if (style.test(edge)) total = total + value.toInt();
2601	});
2602	return total;
2603};
2604
2605var isVisible = function(el){
2606	return !!(!el || el.offsetHeight || el.offsetWidth);
2607};
2608
2609
2610Element.implement({
2611
2612	measure: function(fn){
2613		if (isVisible(this)) return fn.call(this);
2614		var parent = this.getParent(),
2615			toMeasure = [];
2616		while (!isVisible(parent) && parent != document.body){
2617			toMeasure.push(parent.expose());
2618			parent = parent.getParent();
2619		}
2620		var restore = this.expose(),
2621			result = fn.call(this);
2622		restore();
2623		toMeasure.each(function(restore){
2624			restore();
2625		});
2626		return result;
2627	},
2628
2629	expose: function(){
2630		if (this.getStyle('display') != 'none') return function(){};
2631		var before = this.style.cssText;
2632		this.setStyles({
2633			display: 'block',
2634			position: 'absolute',
2635			visibility: 'hidden'
2636		});
2637		return function(){
2638			this.style.cssText = before;
2639		}.bind(this);
2640	},
2641
2642	getDimensions: function(options){
2643		options = Object.merge({computeSize: false}, options);
2644		var dim = {x: 0, y: 0};
2645
2646		var getSize = function(el, options){
2647			return (options.computeSize) ? el.getComputedSize(options) : el.getSize();
2648		};
2649
2650		var parent = this.getParent('body');
2651
2652		if (parent && this.getStyle('display') == 'none'){
2653			dim = this.measure(function(){
2654				return getSize(this, options);
2655			});
2656		} else if (parent){
2657			try { //safari sometimes crashes here, so catch it
2658				dim = getSize(this, options);
2659			}catch(e){}
2660		}
2661
2662		return Object.append(dim, (dim.x || dim.x === 0) ? {
2663				width: dim.x,
2664				height: dim.y
2665			} : {
2666				x: dim.width,
2667				y: dim.height
2668			}
2669		);
2670	},
2671
2672	getComputedSize: function(options){
2673		
2674
2675		options = Object.merge({
2676			styles: ['padding','border'],
2677			planes: {
2678				height: ['top','bottom'],
2679				width: ['left','right']
2680			},
2681			mode: 'both'
2682		}, options);
2683
2684		var styles = {},
2685			size = {width: 0, height: 0},
2686			dimensions;
2687
2688		if (options.mode == 'vertical'){
2689			delete size.width;
2690			delete options.planes.width;
2691		} else if (options.mode == 'horizontal'){
2692			delete size.height;
2693			delete options.planes.height;
2694		}
2695
2696		getStylesList(options.styles, options.planes).each(function(style){
2697			styles[style] = this.getStyle(style).toInt();
2698		}, this);
2699
2700		Object.each(options.planes, function(edges, plane){
2701
2702			var capitalized = plane.capitalize(),
2703				style = this.getStyle(plane);
2704
2705			if (style == 'auto' && !dimensions) dimensions = this.getDimensions();
2706
2707			style = styles[plane] = (style == 'auto') ? dimensions[plane] : style.toInt();
2708			size['total' + capitalized] = style;
2709
2710			edges.each(function(edge){
2711				var edgesize = calculateEdgeSize(edge, styles);
2712				size['computed' + edge.capitalize()] = edgesize;
2713				size['total' + capitalized] += edgesize;
2714			});
2715
2716		}, this);
2717
2718		return Object.append(size, styles);
2719	}
2720
2721});
2722
2723})();
2724
2725
2726/*
2727---
2728
2729script: Element.Pin.js
2730
2731name: Element.Pin
2732
2733description: Extends the Element native object to include the pin method useful for fixed positioning for elements.
2734
2735license: MIT-style license
2736
2737authors:
2738  - Aaron Newton
2739
2740requires:
2741  - Core/Element.Event
2742  - Core/Element.Dimensions
2743  - Core/Element.Style
2744  - /MooTools.More
2745
2746provides: [Element.Pin]
2747
2748...
2749*/
2750
2751(function(){
2752	var supportsPositionFixed = false,
2753		supportTested = false;
2754
2755	var testPositionFixed = function(){
2756		var test = new Element('div').setStyles({
2757			position: 'fixed',
2758			top: 0,
2759			right: 0
2760		}).inject(document.body);
2761		supportsPositionFixed = (test.offsetTop === 0);
2762		test.dispose();
2763		supportTested = true;
2764	};
2765
2766	Element.implement({
2767
2768		pin: function(enable, forceScroll){
2769			if (!supportTested) testPositionFixed();
2770			if (this.getStyle('display') == 'none') return this;
2771
2772			var pinnedPosition,
2773				scroll = window.getScroll(),
2774				parent,
2775				scrollFixer;
2776
2777			if (enable !== false){
2778				pinnedPosition = this.getPosition(supportsPositionFixed ? document.body : this.getOffsetParent());
2779				if (!this.retrieve('pin:_pinned')){
2780					var currentPosition = {
2781						top: pinnedPosition.y - scroll.y,
2782						left: pinnedPosition.x - scroll.x
2783					};
2784
2785					if (supportsPositionFixed && !forceScroll){
2786						this.setStyle('position', 'fixed').setStyles(currentPosition);
2787					} else {
2788
2789						parent = this.getOffsetParent();
2790						var position = this.getPosition(parent),
2791							styles = this.getStyles('left', 'top');
2792
2793						if (parent && styles.left == 'auto' || styles.top == 'auto') this.setPosition(position);
2794						if (this.getStyle('position') == 'static') this.setStyle('position', 'absolute');
2795
2796						position = {
2797							x: styles.left.toInt() - scroll.x,
2798							y: styles.top.toInt() - scroll.y
2799						};
2800
2801						scrollFixer = function(){
2802							if (!this.retrieve('pin:_pinned')) return;
2803							var scroll = window.getScroll();
2804							this.setStyles({
2805								left: position.x + scroll.x,
2806								top: position.y + scroll.y
2807							});
2808						}.bind(this);
2809
2810						this.store('pin:_scrollFixer', scrollFixer);
2811						window.addEvent('scroll', scrollFixer);
2812					}
2813					this.store('pin:_pinned', true);
2814				}
2815
2816			} else {
2817				if (!this.retrieve('pin:_pinned')) return this;
2818
2819				parent = this.getParent();
2820				var offsetParent = (parent.getComputedStyle('position') != 'static' ? parent : parent.getOffsetParent());
2821
2822				pinnedPosition = this.getPosition(offsetParent);
2823
2824				this.store('pin:_pinned', false);
2825				scrollFixer = this.retrieve('pin:_scrollFixer');
2826				if (!scrollFixer){
2827					this.setStyles({
2828						position: 'absolute',
2829						top: pinnedPosition.y + scroll.y,
2830						left: pinnedPosition.x + scroll.x
2831					});
2832				} else {
2833					this.store('pin:_scrollFixer', null);
2834					window.removeEvent('scroll', scrollFixer);
2835				}
2836				this.removeClass('isPinned');
2837			}
2838			return this;
2839		},
2840
2841		unpin: function(){
2842			return this.pin(false);
2843		},
2844
2845		togglePin: function(){
2846			return this.pin(!this.retrieve('pin:_pinned'));
2847		}
2848
2849	});
2850
2851
2852
2853})();
2854
2855
2856/*
2857---
2858
2859script: Element.Position.js
2860
2861name: Element.Position
2862
2863description: Extends the Element native object to include methods useful positioning elements relative to others.
2864
2865license: MIT-style license
2866
2867authors:
2868  - Aaron Newton
2869  - Jacob Thornton
2870
2871requires:
2872  - Core/Options
2873  - Core/Element.Dimensions
2874  - Element.Measure
2875
2876provides: [Element.Position]
2877
2878...
2879*/
2880
2881(function(original){
2882
2883var local = Element.Position = {
2884
2885	options: {/*
2886		edge: false,
2887		returnPos: false,
2888		minimum: {x: 0, y: 0},
2889		maximum: {x: 0, y: 0},
2890		relFixedPosition: false,
2891		ignoreMargins: false,
2892		ignoreScroll: false,
2893		allowNegative: false,*/
2894		relativeTo: document.body,
2895		position: {
2896			x: 'center', //left, center, right
2897			y: 'center' //top, center, bottom
2898		},
2899		offset: {x: 0, y: 0}
2900	},
2901
2902	getOptions: function(element, options){
2903		options = Object.merge({}, local.options, options);
2904		local.setPositionOption(options);
2905		local.setEdgeOption(options);
2906		local.setOffsetOption(element, options);
2907		local.setDimensionsOption(element, options);
2908		return options;
2909	},
2910
2911	setPositionOption: function(options){
2912		options.position = local.getCoordinateFromValue(options.position);
2913	},
2914
2915	setEdgeOption: function(options){
2916		var edgeOption = local.getCoordinateFromValue(options.edge);
2917		options.edge = edgeOption ? edgeOption :
2918			(options.position.x == 'center' && options.position.y == 'center') ? {x: 'center', y: 'center'} :
2919			{x: 'left', y: 'top'};
2920	},
2921
2922	setOffsetOption: function(element, options){
2923		var parentOffset = {x: 0, y: 0},
2924			offsetParent = element.measure(function(){
2925				return document.id(this.getOffsetParent());
2926			}),
2927			parentScroll = offsetParent.getScroll();
2928
2929		if (!offsetParent || offsetParent == element.getDocument().body) return;
2930		parentOffset = offsetParent.measure(function(){
2931			var position = this.getPosition();
2932			if (this.getStyle('position') == 'fixed'){
2933				var scroll = window.getScroll();
2934				position.x += scroll.x;
2935				position.y += scroll.y;
2936			}
2937			return position;
2938		});
2939
2940		options.offset = {
2941			parentPositioned: offsetParent != document.id(options.relativeTo),
2942			x: options.offset.x - parentOffset.x + parentScroll.x,
2943			y: options.offset.y - parentOffset.y + parentScroll.y
2944		};
2945	},
2946
2947	setDimensionsOption: function(element, options){
2948		options.dimensions = element.getDimensions({
2949			computeSize: true,
2950			styles: ['padding', 'border', 'margin']
2951		});
2952	},
2953
2954	getPosition: function(element, options){
2955		var position = {};
2956		options = local.getOptions(element, options);
2957		var relativeTo = document.id(options.relativeTo) || document.body;
2958
2959		local.setPositionCoordinates(options, position, relativeTo);
2960		if (options.edge) local.toEdge(position, options);
2961
2962		var offset = options.offset;
2963		position.left = ((position.x >= 0 || offset.parentPositioned || options.allowNegative) ? position.x : 0).toInt();
2964		position.top = ((position.y >= 0 || offset.parentPositioned || options.allowNegative) ? position.y : 0).toInt();
2965
2966		local.toMinMax(position, options);
2967
2968		if (options.relFixedPosition || relativeTo.getStyle('position') == 'fixed') local.toRelFixedPosition(relativeTo, position);
2969		if (options.ignoreScroll) local.toIgnoreScroll(relativeTo, position);
2970		if (options.ignoreMargins) local.toIgnoreMargins(position, options);
2971
2972		position.left = Math.ceil(position.left);
2973		position.top = Math.ceil(position.top);
2974		delete position.x;
2975		delete position.y;
2976
2977		return position;
2978	},
2979
2980	setPositionCoordinates: function(options, position, relativeTo){
2981		var offsetY = options.offset.y,
2982			offsetX = options.offset.x,
2983			calc = (relativeTo == document.body) ? window.getScroll() : relativeTo.getPosition(),
2984			top = calc.y,
2985			left = calc.x,
2986			winSize = window.getSize();
2987
2988		switch(options.position.x){
2989			case 'left': position.x = left + offsetX; break;
2990			case 'right': position.x = left + offsetX + relativeTo.offsetWidth; break;
2991			default: position.x = left + ((relativeTo == document.body ? winSize.x : relativeTo.offsetWidth) / 2) + offsetX; break;
2992		}
2993
2994		switch(options.position.y){
2995			case 'top': position.y = top + offsetY; break;
2996			case 'bottom': position.y = top + offsetY + relativeTo.offsetHeight; break;
2997			default: position.y = top + ((relativeTo == document.body ? winSize.y : relativeTo.offsetHeight) / 2) + offsetY; break;
2998		}
2999	},
3000
3001	toMinMax: function(position, options){
3002		var xy = {left: 'x', top: 'y'}, value;
3003		['minimum', 'maximum'].each(function(minmax){
3004			['left', 'top'].each(function(lr){
3005				value = options[minmax] ? options[minmax][xy[lr]] : null;
3006				if (value != null && ((minmax == 'minimum') ? position[lr] < value : position[lr] > value)) position[lr] = value;
3007			});
3008		});
3009	},
3010
3011	toRelFixedPosition: function(relativeTo, position){
3012		var winScroll = window.getScroll();
3013		position.top += winScroll.y;
3014		position.left += winScroll.x;
3015	},
3016
3017	toIgnoreScroll: function(relativeTo, position){
3018		var relScroll = relativeTo.getScroll();
3019		position.top -= relScroll.y;
3020		position.left -= relScroll.x;
3021	},
3022
3023	toIgnoreMargins: function(position, options){
3024		position.left += options.edge.x == 'right'
3025			? options.dimensions['margin-right']
3026			: (options.edge.x != 'center'
3027				? -options.dimensions['margin-left']
3028				: -options.dimensions['margin-left'] + ((options.dimensions['margin-right'] + options.dimensions['margin-left']) / 2));
3029
3030		position.top += options.edge.y == 'bottom'
3031			? options.dimensions['margin-bottom']
3032			: (options.edge.y != 'center'
3033				? -options.dimensions['margin-top']
3034				: -options.dimensions['margin-top'] + ((options.dimensions['margin-bottom'] + options.dimensions['margin-top']) / 2));
3035	},
3036
3037	toEdge: function(position, options){
3038		var edgeOffset = {},
3039			dimensions = options.dimensions,
3040			edge = options.edge;
3041
3042		switch(edge.x){
3043			case 'left': edgeOffset.x = 0; break;
3044			case 'right': edgeOffset.x = -dimensions.x - dimensions.computedRight - dimensions.computedLeft; break;
3045			// center
3046			default: edgeOffset.x = -(Math.round(dimensions.totalWidth / 2)); break;
3047		}
3048
3049		switch(edge.y){
3050			case 'top': edgeOffset.y = 0; break;
3051			case 'bottom': edgeOffset.y = -dimensions.y - dimensions.computedTop - dimensions.computedBottom; break;
3052			// center
3053			default: edgeOffset.y = -(Math.round(dimensions.totalHeight / 2)); break;
3054		}
3055
3056		position.x += edgeOffset.x;
3057		position.y += edgeOffset.y;
3058	},
3059
3060	getCoordinateFromValue: function(option){
3061		if (typeOf(option) != 'string') return option;
3062		option = option.toLowerCase();
3063
3064		return {
3065			x: option.test('left') ? 'left'
3066				: (option.test('right') ? 'right' : 'center'),
3067			y: option.test(/upper|top/) ? 'top'
3068				: (option.test('bottom') ? 'bottom' : 'center')
3069		};
3070	}
3071
3072};
3073
3074Element.implement({
3075
3076	position: function(options){
3077		if (options && (options.x != null || options.y != null)){
3078			return (original ? original.apply(this, arguments) : this);
3079		}
3080		var position = this.setStyle('position', 'absolute').calculatePosition(options);
3081		return (options && options.returnPos) ? position : this.setStyles(position);
3082	},
3083
3084	calculatePosition: function(options){
3085		return local.getPosition(this, options);
3086	}
3087
3088});
3089
3090})(Element.prototype.position);
3091
3092
3093/*
3094---
3095
3096script: Element.Shortcuts.js
3097
3098name: Element.Shortcuts
3099
3100description: Extends the Element native object to include some shortcut methods.
3101
3102license: MIT-style license
3103
3104authors:
3105  - Aaron Newton
3106
3107requires:
3108  - Core/Element.Style
3109  - /MooTools.More
3110
3111provides: [Element.Shortcuts]
3112
3113...
3114*/
3115
3116Element.implement({
3117
3118	isDisplayed: function(){
3119		return this.getStyle('display') != 'none';
3120	},
3121
3122	isVisible: function(){
3123		var w = this.offsetWidth,
3124			h = this.offsetHeight;
3125		return (w == 0 && h == 0) ? false : (w > 0 && h > 0) ? true : this.style.display != 'none';
3126	},
3127
3128	toggle: function(){
3129		return this[this.isDisplayed() ? 'hide' : 'show']();
3130	},
3131
3132	hide: function(){
3133		var d;
3134		try {
3135			//IE fails here if the element is not in the dom
3136			d = this.getStyle('display');
3137		} catch(e){}
3138		if (d == 'none') return this;
3139		return this.store('element:_originalDisplay', d || '').setStyle('display', 'none');
3140	},
3141
3142	show: function(display){
3143		if (!display && this.isDisplayed()) return this;
3144		display = display || this.retrieve('element:_originalDisplay') || 'block';
3145		return this.setStyle('display', (display == 'none') ? 'block' : display);
3146	},
3147
3148	swapClass: function(remove, add){
3149		return this.removeClass(remove).addClass(add);
3150	}
3151
3152});
3153
3154Document.implement({
3155
3156	clearSelection: function(){
3157		if (window.getSelection){
3158			var selection = window.getSelection();
3159			if (selection && selection.removeAllRanges) selection.removeAllRanges();
3160		} else if (document.selection && document.selection.empty){
3161			try {
3162				//IE fails here if selected element is not in dom
3163				document.selection.empty();
3164			} catch(e){}
3165		}
3166	}
3167
3168});
3169
3170
3171/*
3172---
3173
3174script: IframeShim.js
3175
3176name: IframeShim
3177
3178description: Defines IframeShim, a class for obscuring select lists and flash objects in IE.
3179
3180license: MIT-style license
3181
3182authors:
3183  - Aaron Newton
3184
3185requires:
3186  - Core/Element.Event
3187  - Core/Element.Style
3188  - Core/Options
3189  - Core/Events
3190  - /Element.Position
3191  - /Class.Occlude
3192
3193provides: [IframeShim]
3194
3195...
3196*/
3197
3198var IframeShim = new Class({
3199
3200	Implements: [Options, Events, Class.Occlude],
3201
3202	options: {
3203		className: 'iframeShim',
3204		src: 'javascript:false;document.write("");',
3205		display: false,
3206		zIndex: null,
3207		margin: 0,
3208		offset: {x: 0, y: 0},
3209		browsers: (Browser.ie6 || (Browser.firefox && Browser.version < 3 && Browser.Platform.mac))
3210	},
3211
3212	property: 'IframeShim',
3213
3214	initialize: function(element, options){
3215		this.element = document.id(element);
3216		if (this.occlude()) return this.occluded;
3217		this.setOptions(options);
3218		this.makeShim();
3219		return this;
3220	},
3221
3222	makeShim: function(){
3223		if (this.options.browsers){
3224			var zIndex = this.element.getStyle('zIndex').toInt();
3225
3226			if (!zIndex){
3227				zIndex = 1;
3228				var pos = this.element.getStyle('position');
3229				if (pos == 'static' || !pos) this.element.setStyle('position', 'relative');
3230				this.element.setStyle('zIndex', zIndex);
3231			}
3232			zIndex = ((this.options.zIndex != null || this.options.zIndex === 0) && zIndex > this.options.zIndex) ? this.options.zIndex : zIndex - 1;
3233			if (zIndex < 0) zIndex = 1;
3234			this.shim = new Element('iframe', {
3235				src: this.options.src,
3236				scrolling: 'no',
3237				frameborder: 0,
3238				styles: {
3239					zIndex: zIndex,
3240					position: 'absolute',
3241					border: 'none',
3242					filter: 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)'
3243				},
3244				'class': this.options.className
3245			}).store('IframeShim', this);
3246			var inject = (function(){
3247				this.shim.inject(this.element, 'after');
3248				this[this.options.display ? 'show' : 'hide']();
3249				this.fireEvent('inject');
3250			}).bind(this);
3251			if (!IframeShim.ready) window.addEvent('load', inject);
3252			else inject();
3253		} else {
3254			this.position = this.hide = this.show = this.dispose = Function.from(this);
3255		}
3256	},
3257
3258	position: function(){
3259		if (!IframeShim.ready || !this.shim) return this;
3260		var size = this.element.measure(function(){
3261			return this.getSize();
3262		});
3263		if (this.options.margin != undefined){
3264			size.x = size.x - (this.options.margin * 2);
3265			size.y = size.y - (this.options.margin * 2);
3266			this.options.offset.x += this.options.margin;
3267			this.options.offset.y += this.options.margin;
3268		}
3269		this.shim.set({width: size.x, height: size.y}).position({
3270			relativeTo: this.element,
3271			offset: this.options.offset
3272		});
3273		return this;
3274	},
3275
3276	hide: function(){
3277		if (this.shim) this.shim.setStyle('display', 'none');
3278		return this;
3279	},
3280
3281	show: function(){
3282		if (this.shim) this.shim.setStyle('display', 'block');
3283		return this.position();
3284	},
3285
3286	dispose: function(){
3287		if (this.shim) this.shim.dispose();
3288		return this;
3289	},
3290
3291	destroy: function(){
3292		if (this.shim) this.shim.destroy();
3293		return this;
3294	}
3295
3296});
3297
3298window.addEvent('load', function(){
3299	IframeShim.ready = true;
3300});
3301
3302
3303/*
3304---
3305
3306script: Mask.js
3307
3308name: Mask
3309
3310description: Creates a mask element to cover another.
3311
3312license: MIT-style license
3313
3314authors:
3315  - Aaron Newton
3316
3317requires:
3318  - Core/Options
3319  - Core/Events
3320  - Core/Element.Event
3321  - /Class.Binds
3322  - /Element.Position
3323  - /IframeShim
3324
3325provides: [Mask]
3326
3327...
3328*/
3329
3330var Mask = new Class({
3331
3332	Implements: [Options, Events],
3333
3334	Binds: ['position'],
3335
3336	options: {/*
3337		onShow: function(){},
3338		onHide: function(){},
3339		onDestroy: function(){},
3340		onClick: function(event){},
3341		inject: {
3342			where: 'after',
3343			target: null,
3344		},
3345		hideOnClick: false,
3346		id: null,
3347		destroyOnHide: false,*/
3348		style: {},
3349		'class': 'mask',
3350		maskMargins: false,
3351		useIframeShim: true,
3352		iframeShimOptions: {}
3353	},
3354
3355	initialize: function(target, options){
3356		this.target = document.id(target) || document.id(document.body);
3357		this.target.store('mask', this);
3358		this.setOptions(options);
3359		this.render();
3360		this.inject();
3361	},
3362
3363	render: function(){
3364		this.element = new Element('div', {
3365			'class': this.options['class'],
3366			id: this.options.id || 'mask-' + String.uniqueID(),
3367			styles: Object.merge({}, this.options.style, {
3368				display: 'none'
3369			}),
3370			events: {
3371				click: function(event){
3372					this.fireEvent('click', event);
3373					if (this.options.hideOnClick) this.hide();
3374				}.bind(this)
3375			}
3376		});
3377
3378		this.hidden = true;
3379	},
3380
3381	toElement: function(){
3382		return this.element;
3383	},
3384
3385	inject: function(target, where){
3386		where = where || (this.options.inject ? this.options.inject.where : '') || this.target == document.body ? 'inside' : 'after';
3387		target = target || (this.options.inject && this.options.inject.target) || this.target;
3388
3389		this.element.inject(target, where);
3390
3391		if (this.options.useIframeShim){
3392			this.shim = new IframeShim(this.element, this.options.iframeShimOptions);
3393
3394			this.addEvents({
3395				show: this.shim.show.bind(this.shim),
3396				hide: this.shim.hide.bind(this.shim),
3397				destroy: this.shim.destroy.bind(this.shim)
3398			});
3399		}
3400	},
3401
3402	position: function(){
3403		this.resize(this.options.width, this.options.height);
3404
3405		this.element.position({
3406			relativeTo: this.target,
3407			position: 'topLeft',
3408			ignoreMargins: !this.options.maskMargins,
3409			ignoreScroll: this.target == document.body
3410		});
3411
3412		return this;
3413	},
3414
3415	resize: function(x, y){
3416		var opt = {
3417			styles: ['padding', 'border']
3418		};
3419		if (this.options.maskMargins) opt.styles.push('margin');
3420
3421		var dim = this.target.getComputedSize(opt);
3422		if (this.target == document.body){
3423			this.element.setStyles({width: 0, height: 0});
3424			var win = window.getScrollSize();
3425			if (dim.totalHeight < win.y) dim.totalHeight = win.y;
3426			if (dim.totalWidth < win.x) dim.totalWidth = win.x;
3427		}
3428		this.element.setStyles({
3429			width: Array.pick([x, dim.totalWidth, dim.x]),
3430			height: Array.pick([y, dim.totalHeight, dim.y])
3431		});
3432
3433		return this;
3434	},
3435
3436	show: function(){
3437		if (!this.hidden) return this;
3438
3439		window.addEvent('resize', this.position);
3440		this.position();
3441		this.showMask.apply(this, arguments);
3442
3443		return this;
3444	},
3445
3446	showMask: function(){
3447		this.element.setStyle('display', 'block');
3448		this.hidden = false;
3449		this.fireEvent('show');
3450	},
3451
3452	hide: function(){
3453		if (this.hidden) return this;
3454
3455		window.removeEvent('resize', this.position);
3456		this.hideMask.apply(this, arguments);
3457		if (this.options.destroyOnHide) return this.destroy();
3458
3459		return this;
3460	},
3461
3462	hideMask: function(){
3463		this.element.setStyle('display', 'none');
3464		this.hidden = true;
3465		this.fireEvent('hide');
3466	},
3467
3468	toggle: function(){
3469		this[this.hidden ? 'show' : 'hide']();
3470	},
3471
3472	destroy: function(){
3473		this.hide();
3474		this.element.destroy();
3475		this.fireEvent('destroy');
3476		this.target.eliminate('mask');
3477	}
3478
3479});
3480
3481Element.Properties.mask = {
3482
3483	set: function(options){
3484		var mask = this.retrieve('mask');
3485		if (mask) mask.destroy();
3486		return this.eliminate('mask').store('mask:options', options);
3487	},
3488
3489	get: function(){
3490		var mask = this.retrieve('mask');
3491		if (!mask){
3492			mask = new Mask(this, this.retrieve('mask:options'));
3493			this.store('mask', mask);
3494		}
3495		return mask;
3496	}
3497
3498};
3499
3500Element.implement({
3501
3502	mask: function(options){
3503		if (options) this.set('mask', options);
3504		this.get('mask').show();
3505		return this;
3506	},
3507
3508	unmask: function(){
3509		this.get('mask').hide();
3510		return this;
3511	}
3512
3513});
3514
3515
3516/*
3517---
3518
3519script: Spinner.js
3520
3521name: Spinner
3522
3523description: Adds a semi-transparent overlay over a dom element with a spinnin ajax icon.
3524
3525license: MIT-style license
3526
3527authors:
3528  - Aaron Newton
3529
3530requires:
3531  - Core/Fx.Tween
3532  - Core/Request
3533  - /Class.refactor
3534  - /Mask
3535
3536provides: [Spinner]
3537
3538...
3539*/
3540
3541var Spinner = new Class({
3542
3543	Extends: Mask,
3544
3545	Implements: Chain,
3546
3547	options: {/*
3548		message: false,*/
3549		'class': 'spinner',
3550		containerPosition: {},
3551		content: {
3552			'class': 'spinner-content'
3553		},
3554		messageContainer: {
3555			'class': 'spinner-msg'
3556		},
3557		img: {
3558			'class': 'spinner-img'
3559		},
3560		fxOptions: {
3561			link: 'chain'
3562		}
3563	},
3564
3565	initialize: function(target, options){
3566		this.target = document.id(target) || document.id(document.body);
3567		this.target.store('spinner', this);
3568		this.setOptions(options);
3569		this.render();
3570		this.inject();
3571
3572		// Add this to events for when noFx is true; parent methods handle hide/show.
3573		var deactivate = function(){ this.active = false; }.bind(this);
3574		this.addEvents({
3575			hide: deactivate,
3576			show: deactivate
3577		});
3578	},
3579
3580	render: function(){
3581		this.parent();
3582
3583		this.element.set('id', this.options.id || 'spinner-' + String.uniqueID());
3584
3585		this.content = document.id(this.options.content) || new Element('div', this.options.content);
3586		this.content.inject(this.element);
3587
3588		if (this.options.message){
3589			this.msg = document.id(this.options.message) || new Element('p', this.options.messageContainer).appendText(this.options.message);
3590			this.msg.inject(this.content);
3591		}
3592
3593		if (this.options.img){
3594			this.img = document.id(this.options.img) || new Element('div', this.options.img);
3595			this.img.inject(this.content);
3596		}
3597
3598		this.element.set('tween', this.options.fxOptions);
3599	},
3600
3601	show: function(noFx){
3602		if (this.active) return this.chain(this.show.bind(this));
3603		if (!this.hidden){
3604			this.callChain.delay(20, this);
3605			return this;
3606		}
3607
3608		this.active = true;
3609
3610		return this.parent(noFx);
3611	},
3612
3613	showMask: function(noFx){
3614		var pos = function(){
3615			this.content.position(Object.merge({
3616				relativeTo: this.element
3617			}, this.options.containerPosition));
3618		}.bind(this);
3619
3620		if (noFx){
3621			this.parent();
3622			pos();
3623		} else {
3624			if (!this.options.style.opacity) this.options.style.opacity = this.element.getStyle('opacity').toFloat();
3625			this.element.setStyles({
3626				display: 'block',
3627				opacity: 0
3628			}).tween('opacity', this.options.style.opacity);
3629			pos();
3630			this.hidden = false;
3631			this.fireEvent('show');
3632			this.callChain();
3633		}
3634	},
3635
3636	hide: function(noFx){
3637		if (this.active) return this.chain(this.hide.bind(this));
3638		if (this.hidden){
3639			this.callChain.delay(20, this);
3640			return this;
3641		}
3642		this.active = true;
3643		return this.parent(noFx);
3644	},
3645
3646	hideMask: function(noFx){
3647		if (noFx) return this.parent();
3648		this.element.tween('opacity', 0).get('tween').chain(function(){
3649			this.element.setStyle('display', 'none');
3650			this.hidden = true;
3651			this.fireEvent('hide');
3652			this.callChain();
3653		}.bind(this));
3654	},
3655
3656	destroy: function(){
3657		this.content.destroy();
3658		this.parent();
3659		this.target.eliminate('spinner');
3660	}
3661
3662});
3663
3664Request = Class.refactor(Request, {
3665
3666	options: {
3667		useSpinner: false,
3668		spinnerOptions: {},
3669		spinnerTarget: false
3670	},
3671
3672	initialize: function(options){
3673		this._send = this.send;
3674		this.send = function(options){
3675			var spinner = this.getSpinner();
3676			if (spinner) spinner.chain(this._send.pass(options, this)).show();
3677			else this._send(options);
3678			return this;
3679		};
3680		this.previous(options);
3681	},
3682
3683	getSpinner: function(){
3684		if (!this.spinner){
3685			var update = document.id(this.options.spinnerTarget) || document.id(this.options.update);
3686			if (this.options.useSpinner && update){
3687				update.set('spinner', this.options.spinnerOptions);
3688				var spinner = this.spinner = update.get('spinner');
3689				['complete', 'exception', 'cancel'].each(function(event){
3690					this.addEvent(event, spinner.hide.bind(spinner));
3691				}, this);
3692			}
3693		}
3694		return this.spinner;
3695	}
3696
3697});
3698
3699Element.Properties.spinner = {
3700
3701	set: function(options){
3702		var spinner = this.retrieve('spinner');
3703		if (spinner) spinner.destroy();
3704		return this.eliminate('spinner').store('spinner:options', options);
3705	},
3706
3707	get: function(){
3708		var spinner = this.retrieve('spinner');
3709		if (!spinner){
3710			spinner = new Spinner(this, this.retrieve('spinner:options'));
3711			this.store('spinner', spinner);
3712		}
3713		return spinner;
3714	}
3715
3716};
3717
3718Element.implement({
3719
3720	spin: function(options){
3721		if (options) this.set('spinner', options);
3722		this.get('spinner').show();
3723		return this;
3724	},
3725
3726	unspin: function(){
3727		this.get('spinner').hide();
3728		return this;
3729	}
3730
3731});
3732
3733
3734/*
3735---
3736
3737script: Form.Request.js
3738
3739name: Form.Request
3740
3741description: Handles the basic functionality of submitting a form and updating a dom element with the result.
3742
3743license: MIT-style license
3744
3745authors:
3746  - Aaron Newton
3747
3748requires:
3749  - Core/Request.HTML
3750  - /Class.Binds
3751  - /Class.Occlude
3752  - /Spinner
3753  - /String.QueryString
3754  - /Element.Delegation
3755
3756provides: [Form.Request]
3757
3758...
3759*/
3760
3761if (!window.Form) window.Form = {};
3762
3763(function(){
3764
3765	Form.Request = new Class({
3766
3767		Binds: ['onSubmit', 'onFormValidate'],
3768
3769		Implements: [Options, Events, Class.Occlude],
3770
3771		options: {/*
3772			onFailure: function(){},
3773			onSuccess: function(){}, // aliased to onComplete,
3774			onSend: function(){}*/
3775			requestOptions: {
3776				evalScripts: true,
3777				useSpinner: true,
3778				emulation: false,
3779				link: 'ignore'
3780			},
3781			sendButtonClicked: true,
3782			extraData: {},
3783			resetForm: true
3784		},
3785
3786		property: 'form.request',
3787
3788		initialize: function(form, target, options){
3789			this.element = document.id(form);
3790			if (this.occlude()) return this.occluded;
3791			this.setOptions(options)
3792				.setTarget(target)
3793				.attach();
3794		},
3795
3796		setTarget: function(target){
3797			this.target = document.id(target);
3798			if (!this.request){
3799				this.makeRequest();
3800			} else {
3801				this.request.setOptions({
3802					update: this.target
3803				});
3804			}
3805			return this;
3806		},
3807
3808		toElement: function(){
3809			return this.element;
3810		},
3811
3812		makeRequest: function(){
3813			var self = this;
3814			this.request = new Request.HTML(Object.merge({
3815					update: this.target,
3816					emulation: false,
3817					spinnerTarget: this.element,
3818					method: this.element.get('method') || 'post'
3819			}, this.options.requestOptions)).addEvents({
3820				success: function(tree, elements, html, javascript){
3821					['complete', 'success'].each(function(evt){
3822						self.fireEvent(evt, [self.target, tree, elements, html, javascript]);
3823					});
3824				},
3825				failure: function(){
3826					self.fireEvent('complete', arguments).fireEvent('failure', arguments);
3827				},
3828				exception: function(){
3829					self.fireEvent('failure', arguments);
3830				}
3831			});
3832			return this.attachReset();
3833		},
3834
3835		attachReset: function(){
3836			if (!this.options.resetForm) return this;
3837			this.request.addEvent('success', function(){
3838				Function.attempt(function(){
3839					this.element.reset();
3840				}.bind(this));
3841				if (window.OverText) OverText.update();
3842			}.bind(this));
3843			return this;
3844		},
3845
3846		attach: function(attach){
3847			var method = (attach != false) ? 'addEvent' : 'removeEvent';
3848			this.element[method]('click:relay(button, input[type=submit])', this.saveClickedButton.bind(this));
3849
3850			var fv = this.element.retrieve('validator');
3851			if (fv) fv[method]('onFormValidate', this.onFormValidate);
3852			else this.element[method]('submit', this.onSubmit);
3853
3854			return this;
3855		},
3856
3857		detach: function(){
3858			return this.attach(false);
3859		},
3860
3861		//public method
3862		enable: function(){
3863			return this.attach();
3864		},
3865
3866		//public method
3867		disable: function(){
3868			return this.detach();
3869		},
3870
3871		onFormValidate: function(valid, form, event){
3872			//if there's no event, then this wasn't a submit event
3873			if (!event) return;
3874			var fv = this.element.retrieve('validator');
3875			if (valid || (fv && !fv.options.stopOnFailure)){
3876				event.stop();
3877				this.send();
3878			}
3879		},
3880
3881		onSubmit: function(event){
3882			var fv = this.element.retrieve('validator');
3883			if (fv){
3884				//form validator was created after Form.Request
3885				this.element.removeEvent('submit', this.onSubmit);
3886				fv.addEvent('onFormValidate', this.onFormValidate);
3887				this.element.validate();
3888				return;
3889			}
3890			if (event) event.stop();
3891			this.send();
3892		},
3893
3894		saveClickedButton: function(event, target){
3895			var targetName = target.get('name');
3896			if (!targetName || !this.options.sendButtonClicked) return;
3897			this.options.extraData[targetName] = target.get('value') || true;
3898			this.clickedCleaner = function(){
3899				delete this.options.extraData[targetName];
3900				this.clickedCleaner = function(){};
3901			}.bind(this);
3902		},
3903
3904		clickedCleaner: function(){},
3905
3906		send: function(){
3907			var str = this.element.toQueryString().trim(),
3908				data = Object.toQueryString(this.options.extraData);
3909
3910			if (str) str += "&" + data;
3911			else str = data;
3912
3913			this.fireEvent('send', [this.element, str.parseQueryString()]);
3914			this.request.send({
3915				data: str,
3916				url: this.options.requestOptions.url || this.element.get('action')
3917			});
3918			this.clickedCleaner();
3919			return this;
3920		}
3921
3922	});
3923
3924	Element.implement('formUpdate', function(update, options){
3925		var fq = this.retrieve('form.request');
3926		if (!fq){
3927			fq = new Form.Request(this, update, options);
3928		} else {
3929			if (update) fq.setTarget(update);
3930			if (options) fq.setOptions(options).makeRequest();
3931		}
3932		fq.send();
3933		return this;
3934	});
3935
3936})();
3937
3938
3939/*
3940---
3941
3942script: Fx.Reveal.js
3943
3944name: Fx.Reveal
3945
3946description: Defines Fx.Reveal, a class that shows and hides elements with a transition.
3947
3948license: MIT-style license
3949
3950authors:
3951  - Aaron Newton
3952
3953requires:
3954  - Core/Fx.Morph
3955  - /Element.Shortcuts
3956  - /Element.Measure
3957
3958provides: [Fx.Reveal]
3959
3960...
3961*/
3962
3963(function(){
3964
3965
3966var hideTheseOf = function(object){
3967	var hideThese = object.options.hideInputs;
3968	if (window.OverText){
3969		var otClasses = [null];
3970		OverText.each(function(ot){
3971			otClasses.include('.' + ot.options.labelClass);
3972		});
3973		if (otClasses) hideThese += otClasses.join(', ');
3974	}
3975	return (hideThese) ? object.element.getElements(hideThese) : null;
3976};
3977
3978
3979Fx.Reveal = new Class({
3980
3981	Extends: Fx.Morph,
3982
3983	options: {/*
3984		onShow: function(thisElement){},
3985		onHide: function(thisElement){},
3986		onComplete: function(thisElement){},
3987		heightOverride: null,
3988		widthOverride: null,*/
3989		link: 'cancel',
3990		styles: ['padding', 'border', 'margin'],
3991		transitionOpacity: !Browser.ie6,
3992		mode: 'vertical',
3993		display: function(){
3994			return this.element.get('tag') != 'tr' ? 'block' : 'table-row';
3995		},
3996		opacity: 1,
3997		hideInputs: Browser.ie ? 'select, input, textarea, object, embed' : null
3998	},
3999
4000	dissolve: function(){
4001		if (!this.hiding && !this.showing){
4002			if (this.element.getStyle('display') != 'none'){
4003				this.hiding = true;
4004				this.showing = false;
4005				this.hidden = true;
4006				this.cssText = this.element.style.cssText;
4007
4008				var startStyles = this.element.getComputedSize({
4009					styles: this.options.styles,
4010					mode: this.options.mode
4011				});
4012				if (this.options.transitionOpacity) startStyles.opacity = this.options.opacity;
4013
4014				var zero = {};
4015				Object.each(startStyles, function(style, name){
4016					zero[name] = [style, 0];
4017				});
4018
4019				this.element.setStyles({
4020					display: Function.from(this.options.display).call(this),
4021					overflow: 'hidden'
4022				});
4023
4024				var hideThese = hideTheseOf(this);
4025				if (hideThese) hideThese.setStyle('visibility', 'hidden');
4026
4027				this.$chain.unshift(function(){
4028					if (this.hidden){
4029						this.hiding = false;
4030						this.element.style.cssText = this.cssText;
4031						this.element.setStyle('display', 'none');
4032						if (hideThese) hideThese.setStyle('visibility', 'visible');
4033					}
4034					this.fireEvent('hide', this.element);
4035					this.callChain();
4036				}.bind(this));
4037
4038				this.start(zero);
4039			} else {
4040				this.callChain.delay(10, this);
4041				this.fireEvent('complete', this.element);
4042				this.fireEvent('hide', this.element);
4043			}
4044		} else if (this.options.link == 'chain'){
4045			this.chain(this.dissolve.bind(this));
4046		} else if (this.options.link == 'cancel' && !this.hiding){
4047			this.cancel();
4048			this.dissolve();
4049		}
4050		return this;
4051	},
4052
4053	reveal: function(){
4054		if (!this.showing && !this.hiding){
4055			if (this.element.getStyle('display') == 'none'){
4056				this.hiding = false;
4057				this.showing = true;
4058				this.hidden = false;
4059				this.cssText = this.element.style.cssText;
4060
4061				var startStyles;
4062				this.element.measure(function(){
4063					startStyles = this.element.getComputedSize({
4064						styles: this.options.styles,
4065						mode: this.options.mode
4066					});
4067				}.bind(this));
4068				if (this.options.heightOverride != null) startStyles.height = this.options.heightOverride.toInt();
4069				if (this.options.widthOverride != null) startStyles.width = this.options.widthOverride.toInt();
4070				if (this.options.transitionOpacity){
4071					this.element.setStyle('opacity', 0);
4072					startStyles.opacity = this.options.opacity;
4073				}
4074
4075				var zero = {
4076					height: 0,
4077					display: Function.from(this.options.display).call(this)
4078				};
4079				Object.each(startStyles, function(style, name){
4080					zero[name] = 0;
4081				});
4082				zero.overflow = 'hidden';
4083
4084				this.element.setStyles(zero);
4085
4086				var hideThese = hideTheseOf(this);
4087				if (hideThese) hideThese.setStyle('visibility', 'hidden');
4088
4089				this.$chain.unshift(function(){
4090					this.element.style.cssText = this.cssText;
4091					this.element.setStyle('display', Function.from(this.options.display).call(this));
4092					if (!this.hidden) this.showing = false;
4093					if (hideThese) hideThese.setStyle('visibility', 'visible');
4094					this.callChain();
4095					this.fireEvent('show', this.element);
4096				}.bind(this));
4097
4098				this.start(startStyles);
4099			} else {
4100				this.callChain();
4101				this.fireEvent('complete', this.element);
4102				this.fireEvent('show', this.element);
4103			}
4104		} else if (this.options.link == 'chain'){
4105			this.chain(this.reveal.bind(this));
4106		} else if (this.options.link == 'cancel' && !this.showing){
4107			this.cancel();
4108			this.reveal();
4109		}
4110		return this;
4111	},
4112
4113	toggle: function(){
4114		if (this.element.getStyle('display') == 'none'){
4115			this.reveal();
4116		} else {
4117			this.dissolve();
4118		}
4119		return this;
4120	},
4121
4122	cancel: function(){
4123		this.parent.apply(this, arguments);
4124		if (this.cssText != null) this.element.style.cssText = this.cssText;
4125		this.hiding = false;
4126		this.showing = false;
4127		return this;
4128	}
4129
4130});
4131
4132Element.Properties.reveal = {
4133
4134	set: function(options){
4135		this.get('reveal').cancel().setOptions(options);
4136		return this;
4137	},
4138
4139	get: function(){
4140		var reveal = this.retrieve('reveal');
4141		if (!reveal){
4142			reveal = new Fx.Reveal(this);
4143			this.store('reveal', reveal);
4144		}
4145		return reveal;
4146	}
4147
4148};
4149
4150Element.Properties.dissolve = Element.Properties.reveal;
4151
4152Element.implement({
4153
4154	reveal: function(options){
4155		this.get('reveal').setOptions(options).reveal();
4156		return this;
4157	},
4158
4159	dissolve: function(options){
4160		this.get('reveal').setOptions(options).dissolve();
4161		return this;
4162	},
4163
4164	nix: function(options){
4165		var params = Array.link(arguments, {destroy: Type.isBoolean, options: Type.isObject});
4166		this.get('reveal').setOptions(options).dissolve().chain(function(){
4167			this[params.destroy ? 'destroy' : 'dispose']();
4168		}.bind(this));
4169		return this;
4170	},
4171
4172	wink: function(){
4173		var params = Array.link(arguments, {duration: Type.isNumber, options: Type.isObject});
4174		var reveal = this.get('reveal').setOptions(params.options);
4175		reveal.reveal().chain(function(){
4176			(function(){
4177				reveal.dissolve();
4178			}).delay(params.duration || 2000);
4179		});
4180	}
4181
4182});
4183
4184})();
4185
4186
4187/*
4188---
4189
4190script: Form.Request.Append.js
4191
4192name: Form.Request.Append
4193
4194description: 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.
4195
4196license: MIT-style license
4197
4198authors:
4199  - Aaron Newton
4200
4201requires:
4202  - /Form.Request
4203  - /Fx.Reveal
4204  - /Elements.from
4205
4206provides: [Form.Request.Append]
4207
4208...
4209*/
4210
4211Form.Request.Append = new Class({
4212
4213	Extends: Form.Request,
4214
4215	options: {
4216		//onBeforeEffect: function(){},
4217		useReveal: true,
4218		revealOptions: {},
4219		inject: 'bottom'
4220	},
4221
4222	makeRequest: function(){
4223		this.request = new Request.HTML(Object.merge({
4224				url: this.element.get('action'),
4225				method: this.element.get('method') || 'post',
4226				spinnerTarget: this.element
4227			}, this.options.requestOptions, {
4228				evalScripts: false
4229			})
4230		).addEvents({
4231			success: function(tree, elements, html, javascript){
4232				var container;
4233				var kids = Elements.from(html);
4234				if (kids.length == 1){
4235					container = kids[0];
4236				} else {
4237					 container = new Element('div', {
4238						styles: {
4239							display: 'none'
4240						}
4241					}).adopt(kids);
4242				}
4243				container.inject(this.target, this.options.inject);
4244				if (this.options.requestOptions.evalScripts) Browser.exec(javascript);
4245				this.fireEvent('beforeEffect', container);
4246				var finish = function(){
4247					this.fireEvent('success', [container, this.target, tree, elements, html, javascript]);
4248				}.bind(this);
4249				if (this.options.useReveal){
4250					container.set('reveal', this.options.revealOptions).get('reveal').chain(finish);
4251					container.reveal();
4252				} else {
4253					finish();
4254				}
4255			}.bind(this),
4256			failure: function(xhr){
4257				this.fireEvent('failure', xhr);
4258			}.bind(this)
4259		});
4260		this.attachReset();
4261	}
4262
4263});
4264
4265
4266/*
4267---
4268
4269name: Locale.en-US.Form.Validator
4270
4271description: Form Validator messages for English.
4272
4273license: MIT-style license
4274
4275authors:
4276  - Aaron Newton
4277
4278requires:
4279  - /Locale
4280
4281provides: [Locale.en-US.Form.Validator]
4282
4283...
4284*/
4285
4286Locale.define('en-US', 'FormValidator', {
4287
4288	required: 'This field is required.',
4289	length: 'Please enter {length} characters (you entered {elLength} characters)',
4290	minLength: 'Please enter at least {minLength} characters (you entered {length} characters).',
4291	maxLength: 'Please enter no more than {maxLength} characters (you entered {length} characters).',
4292	integer: 'Please enter an integer in this field. Numbers with decimals (e.g. 1.25) are not permitted.',
4293	numeric: 'Please enter only numeric values in this field (i.e. "1" or "1.1" or "-1" or "-1.1").',
4294	digits: 'Please use numbers and punctuation only in this field (for example, a phone number with dashes or dots is permitted).',
4295	alpha: 'Please use only letters (a-z) within this field. No spaces or other characters are allowed.',
4296	alphanum: 'Please use only letters (a-z) or numbers (0-9) in this field. No spaces or other characters are allowed.',
4297	dateSuchAs: 'Please enter a valid date such as {date}',
4298	dateInFormatMDY: 'Please enter a valid date such as MM/DD/YYYY (i.e. "12/31/1999")',
4299	email: 'Please enter a valid email address. For example "[email protected]".',
4300	url: 'Please enter a valid URL such as http://www.example.com.',
4301	currencyDollar: 'Please enter a valid $ amount. For example $100.00 .',
4302	oneRequired: 'Please enter something for at least one of these inputs.',
4303	errorPrefix: 'Error: ',
4304	warningPrefix: 'Warning: ',
4305
4306	// Form.Validator.Extras
4307	noSpace: 'There can be no spaces in this input.',
4308	reqChkByNode: 'No items are selected.',
4309	requiredChk: 'This field is required.',
4310	reqChkByName: 'Please select a {label}.',
4311	match: 'This field needs to match the {matchName} field',
4312	startDate: 'the start date',
4313	endDate: 'the end date',
4314	currendDate: 'the current date',
4315	afterDate: 'The date should be the same or after {label}.',
4316	beforeDate: 'The date should be the same or before {label}.',
4317	startMonth: 'Please select a start month',
4318	sameMonth: 'These two dates must be in the same month - you must change one or the other.',
4319	creditcard: 'The credit card number entered is invalid. Please check the number and try again. {length} digits entered.'
4320
4321});
4322
4323
4324/*
4325---
4326
4327script: Form.Validator.js
4328
4329name: Form.Validator
4330
4331description: A css-class based form validation system.
4332
4333license: MIT-style license
4334
4335authors:
4336  - Aaron Newton
4337
4338requires:
4339  - Core/Options
4340  - Core/Events
4341  - Core/Slick.Finder
4342  - Core/Element.Event
4343  - Core/Element.Style
4344  - Core/JSON
4345  - /Locale
4346  - /Class.Binds
4347  - /Date
4348  - /Element.Forms
4349  - /Locale.en-US.Form.Validator
4350  - /Element.Shortcuts
4351
4352provides: [Form.Validator, InputValidator, FormValidator.BaseValidators]
4353
4354...
4355*/
4356if (!window.Form) window.Form = {};
4357
4358var InputValidator = this.InputValidator = new Class({
4359
4360	Implements: [Options],
4361
4362	options: {
4363		errorMsg: 'Validation failed.',
4364		test: Function.from(true)
4365	},
4366
4367	initialize: function(className, options){
4368		this.setOptions(options);
4369		this.className = className;
4370	},
4371
4372	test: function(field, props){
4373		field = document.id(field);
4374		return (field) ? this.options.test(field, props || this.getProps(field)) : false;
4375	},
4376
4377	getError: function(field, props){
4378		field = document.id(field);
4379		var err = this.options.errorMsg;
4380		if (typeOf(err) == 'function') err = err(field, props || this.getProps(field));
4381		return err;
4382	},
4383
4384	getProps: function(field){
4385		field = document.id(field);
4386		return (field) ? field.get('validatorProps') : {};
4387	}
4388
4389});
4390
4391Element.Properties.validators = {
4392
4393	get: function(){
4394		return (this.get('data-validators') || this.className).clean().split(' ');
4395	}
4396
4397};
4398
4399Element.Properties.validatorProps = {
4400
4401	set: function(props){
4402		return this.eliminate('$moo:validatorProps').store('$moo:validatorProps', props);
4403	},
4404
4405	get: function(props){
4406		if (props) this.set(props);
4407		if (this.retrieve('$moo:validatorProps')) return this.retrieve('$moo:validatorProps');
4408		if (this.getProperty('data-validator-properties') || this.getProperty('validatorProps')){
4409			try {
4410				this.store('$moo:validatorProps', JSON.decode(this.getProperty('validatorProps') || this.getProperty('data-validator-properties')));
4411			}catch(e){
4412				return {};
4413			}
4414		} else {
4415			var vals = this.get('validators').filter(function(cls){
4416				return cls.test(':');
4417			});
4418			if (!vals.length){
4419				this.store('$moo:validatorProps', {});
4420			} else {
4421				props = {};
4422				vals.each(function(cls){
4423					var split = cls.split(':');
4424					if (split[1]){
4425						try {
4426							props[split[0]] = JSON.decode(split[1]);
4427						} catch(e){}
4428					}
4429				});
4430				this.store('$moo:validatorProps', props);
4431			}
4432		}
4433		return this.retrieve('$moo:validatorProps');
4434	}
4435
4436};
4437
4438Form.Validator = new Class({
4439
4440	Implements: [Options, Events],
4441
4442	Binds: ['onSubmit'],
4443
4444	options: {/*
4445		onFormValidate: function(isValid, form, event){},
4446		onElementValidate: function(isValid, field, className, warn){},
4447		onElementPass: function(field){},
4448		onElementFail: function(field, validatorsFailed){}, */
4449		fieldSelectors: 'input, select, textarea',
4450		ignoreHidden: true,
4451		ignoreDisabled: true,
4452		useTitles: false,
4453		evaluateOnSubmit: true,
4454		evaluateFieldsOnBlur: true,
4455		evaluateFieldsOnChange: true,
4456		serial: true,
4457		stopOnFailure: true,
4458		warningPrefix: function(){
4459			return Form.Validator.getMsg('warningPrefix') || 'Warning: ';
4460		},
4461		errorPrefix: function(){
4462			return Form.Validator.getMsg('errorPrefix') || 'Error: ';
4463		}
4464	},
4465
4466	initialize: function(form, options){
4467		this.setOptions(options);
4468		this.element = document.id(form);
4469		this.element.store('validator', this);
4470		this.warningPrefix = Function.from(this.options.warningPrefix)();
4471		this.errorPrefix = Function.from(this.options.errorPrefix)();
4472		if (this.options.evaluateOnSubmit) this.element.addEvent('submit', this.onSubmit);
4473		if (this.options.evaluateFieldsOnBlur || this.options.evaluateFieldsOnChange) this.watchFields(this.getFields());
4474	},
4475
4476	toElement: function(){
4477		return this.element;
4478	},
4479
4480	getFields: function(){
4481		return (this.fields = this.element.getElements(this.options.fieldSelectors));
4482	},
4483
4484	watchFields: function(fields){
4485		fields.each(function(el){
4486			if (this.options.evaluateFieldsOnBlur)
4487				el.addEvent('blur', this.validationMonitor.pass([el, false], this));
4488			if (this.options.evaluateFieldsOnChange)
4489				el.addEvent('change', this.validationMonitor.pass([el, true], this));
4490		}, this);
4491	},
4492
4493	validationMonitor: function(){
4494		clearTimeout(this.timer);
4495		this.timer = this.validateField.delay(50, this, arguments);
4496	},
4497
4498	onSubmit: function(event){
4499		if (this.validate(event)) this.reset();
4500	},
4501
4502	reset: function(){
4503		this.getFields().each(this.resetField, this);
4504		return this;
4505	},
4506
4507	validate: function(event){
4508		var result = this.getFields().map(function(field){
4509			return this.validateField(field, true);
4510		}, this).every(function(v){
4511			return v;
4512		});
4513		this.fireEvent('formValidate', [result, this.element, event]);
4514		if (this.options.stopOnFailure && !result && event) event.preventDefault();
4515		return result;
4516	},
4517
4518	validateField: function(field, force){
4519		if (this.paused) return true;
4520		field = document.id(field);
4521		var passed = !field.hasClass('validation-failed');
4522		var failed, warned;
4523		if (this.options.serial && !force){
4524			failed = this.element.getElement('.validation-failed');
4525			warned = this.element.getElement('.warning');
4526		}
4527		if (field && (!failed || force || field.hasClass('validation-failed') || (failed && !this.options.serial))){
4528			var validationTypes = field.get('validators');
4529			var validators = validationTypes.some(function(cn){
4530				return this.getValidator(cn);
4531			}, this);
4532			var validatorsFailed = [];
4533			validationTypes.each(function(className){
4534				if (className && !this.test(className, field)) validatorsFailed.include(className);
4535			}, this);
4536			passed = validatorsFailed.length === 0;
4537			if (validators && !this.hasValidator(field, 'warnOnly')){
4538				if (passed){
4539					field.addClass('validation-passed').removeClass('validation-failed');
4540					this.fireEvent('elementPass', [field]);
4541				} else {
4542					field.addClass('validation-failed').removeClass('validation-passed');
4543					this.fireEvent('elementFail', [field, validatorsFailed]);
4544				}
4545			}
4546			if (!warned){
4547				var warnings = validationTypes.some(function(cn){
4548					if (cn.test('^warn'))
4549						return this.getValidator(cn.replace(/^warn-/,''));
4550					else return null;
4551				}, this);
4552				field.removeClass('warning');
4553				var warnResult = validationTypes.map(function(cn){
4554					if (cn.test('^warn'))
4555						return this.test(cn.replace(/^warn-/,''), field, true);
4556					else return null;
4557				}, this);
4558			}
4559		}
4560		return passed;
4561	},
4562
4563	test: function(className, field, warn){
4564		field = document.id(field);
4565		if ((this.options.ignoreHidden && !field.isVisible()) || (this.options.ignoreDisabled && field.get('disabled'))) return true;
4566		var validator = this.getValidator(className);
4567		if (warn != null) warn = false;
4568		if (this.hasValidator(field, 'warnOnly')) warn = true;
4569		var isValid = this.hasValidator(field, 'ignoreValidation') || (validator ? validator.test(field) : true);
4570		if (validator && field.isVisible()) this.fireEvent('elementValidate', [isValid, field, className, warn]);
4571		if (warn) return true;
4572		return isValid;
4573	},
4574
4575	hasValidator: function(field, value){
4576		return field.get('validators').contains(value);
4577	},
4578
4579	resetField: function(field){
4580		field = document.id(field);
4581		if (field){
4582			field.get('validators').each(function(className){
4583				if (className.test('^warn-')) className = className.replace(/^warn-/, '');
4584				field.removeClass('validation-failed');
4585				field.removeClass('warning');
4586				field.removeClass('validation-passed');
4587			}, this);
4588		}
4589		return this;
4590	},
4591
4592	stop: function(){
4593		this.paused = true;
4594		return this;
4595	},
4596
4597	start: function(){
4598		this.paused = false;
4599		return this;
4600	},
4601
4602	ignoreField: function(field, warn){
4603		field = document.id(field);
4604		if (field){
4605			this.enforceField(field);
4606			if (warn) field.addClass('warnOnly');
4607			else field.addClass('ignoreValidation');
4608		}
4609		return this;
4610	},
4611
4612	enforceField: function(field){
4613		field = document.id(field);
4614		if (field) field.removeClass('warnOnly').removeClass('ignoreValidation');
4615		return this;
4616	}
4617
4618});
4619
4620Form.Validator.getMsg = function(key){
4621	return Locale.get('FormValidator.' + key);
4622};
4623
4624Form.Validator.adders = {
4625
4626	validators:{},
4627
4628	add : function(className, options){
4629		this.validators[className] = new InputValidator(className, options);
4630		//if this is a class (this method is used by instances of Form.Validator and the Form.Validator namespace)
4631		//extend these validators into it
4632		//this allows validators to be global and/or per instance
4633		if (!this.initialize){
4634			this.implement({
4635				validators: this.validators
4636			});
4637		}
4638	},
4639
4640	addAllThese : function(validators){
4641		Array.from(validators).each(function(validator){
4642			this.add(validator[0], validator[1]);
4643		}, this);
4644	},
4645
4646	getValidator: function(className){
4647		return this.validators[className.split(':')[0]];
4648	}
4649
4650};
4651
4652Object.append(Form.Validator, Form.Validator.adders);
4653
4654Form.Validator.implement(Form.Validator.adders);
4655
4656Form.Validator.add('IsEmpty', {
4657
4658	errorMsg: false,
4659	test: function(element){
4660		if (element.type == 'select-one' || element.type == 'select')
4661			return !(element.selectedIndex >= 0 && element.options[element.selectedIndex].value != '');
4662		else
4663			return ((element.get('value') == null) || (element.get('value').length == 0));
4664	}
4665
4666});
4667
4668Form.Validator.addAllThese([
4669
4670	['required', {
4671		errorMsg: function(){
4672			return Form.Validator.getMsg('required');
4673		},
4674		test: function(element){
4675			return !Form.Validator.getValidator('IsEmpty').test(element);
4676		}
4677	}],
4678
4679	['length', {
4680		errorMsg: function(element, props){
4681			if (typeOf(props.length) != 'null')
4682				return Form.Validator.getMsg('length').substitute({length: props.length, elLength: element.get('value').length});
4683			else return '';
4684		},
4685		test: function(element, props){
4686			if (typeOf(props.length) != 'null') return (element.get('value').length == props.length || element.get('value').length == 0);
4687			else return true;
4688		}
4689	}],	
4690
4691	['minLength', {
4692		errorMsg: function(element, props){
4693			if (typeOf(props.minLength) != 'null')
4694				return Form.Validator.getMsg('minLength').substitute({minLength: props.minLength, length: element.get('value').length});
4695			else return '';
4696		},
4697		test: function(element, props){
4698			if (typeOf(props.minLength) != 'null') return (element.get('value').length >= (props.minLength || 0));
4699			else return true;
4700		}
4701	}],
4702
4703	['maxLength', {
4704		errorMsg: function(element, props){
4705			//props is {maxLength:10}
4706			if (typeOf(props.maxLength) != 'null')
4707				return Form.Validator.getMsg('maxLength').substitute({maxLength: props.maxLength, length: element.get('value').length});
4708			else return '';
4709		},
4710		test: function(element, props){
4711			return element.get('value').length <= (props.maxLength || 10000);
4712		}
4713	}],
4714
4715	['validate-integer', {
4716		errorMsg: Form.Validator.getMsg.pass('integer'),
4717		test: function(element){
4718			return Form.Validator.getValidator('IsEmpty').test(element) || (/^(-?[1-9]\d*|0)$/).test(element.get('value'));
4719		}
4720	}],
4721
4722	['validate-numeric', {
4723		errorMsg: Form.Validator.getMsg.pass('numeric'),
4724		test: function(element){
4725			return Form.Validator.getValidator('IsEmpty').test(element) ||
4726				(/^-?(?:0$0(?=\d*\.)|[1-9]|0)\d*(\.\d+)?$/).test(element.get('value'));
4727		}
4728	}],
4729
4730	['validate-digits', {
4731		errorMsg: Form.Validator.getMsg.pass('digits'),
4732		test: function(element){
4733			return Form.Validator.getValidator('IsEmpty').test(element) || (/^[\d() .:\-\+#]+$/.test(element.get('value')));
4734		}
4735	}],
4736
4737	['validate-alpha', {
4738		errorMsg: Form.Validator.getMsg.pass('alpha'),
4739		test: function(element){
4740			return Form.Validator.getValidator('IsEmpty').test(element) || (/^[a-zA-Z]+$/).test(element.get('value'));
4741		}
4742	}],
4743
4744	['validate-alphanum', {
4745		errorMsg: Form.Validator.getMsg.pass('alphanum'),
4746		test: function(element){
4747			return Form.Validator.getValidator('IsEmpty').test(element) || !(/\W/).test(element.get('value'));
4748		}
4749	}],
4750
4751	['validate-date', {
4752		errorMsg: function(element, props){
4753			if (Date.parse){
4754				var format = props.dateFormat || '%x';
4755				return Form.Validator.getMsg('dateSuchAs').substitute({date: new Date().format(format)});
4756			} else {
4757				return Form.Validator.getMsg('dateInFormatMDY');
4758			}
4759		},
4760		test: function(element, props){
4761			if (Form.Validator.getValidator('IsEmpty').test(element)) return true;
4762			var dateLocale = Locale.getCurrent().sets.Date,
4763				dateNouns = new RegExp([dateLocale.days, dateLocale.days_abbr, dateLocale.months, dateLocale.months_abbr].flatten().join('|'), 'i'),
4764				value = element.get('value'),
4765				wordsInValue = value.match(/[a-z]+/gi);
4766
4767				if (wordsInValue && !wordsInValue.every(dateNouns.exec, dateNouns)) return false;
4768
4769				var date = Date.parse(value),
4770					format = props.dateFormat || '%x',
4771					formatted = date.format(format);
4772
4773				if (formatted != 'invalid date') element.set('value', formatted);
4774				return date.isValid();
4775		}
4776	}],
4777
4778	['validate-email', {
4779		errorMsg: Form.Validator.getMsg.pass('email'),
4780		test: function(element){
4781			/*
4782			var chars = "[a-z0-9!#$%&'*+/=?^_`{|}~-]",
4783				local = '(?:' + chars + '\\.?){0,63}' + chars,
4784
4785				label = '[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?',
4786				hostname = '(?:' + label + '\\.)*' + label;
4787
4788				octet = '(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)',
4789				ipv4 = '\\[(?:' + octet + '\\.){3}' + octet + '\\]',
4790
4791				domain = '(?:' + hostname + '|' + ipv4 + ')';
4792
4793			var regex = new RegExp('^' + local + '@' + domain + '$', 'i');
4794			*/
4795			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'));
4796		}
4797	}],
4798
4799	['validate-url', {
4800		errorMsg: Form.Validator.getMsg.pass('url'),
4801		test: function(element){
4802			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'));
4803		}
4804	}],
4805
4806	['validate-currency-dollar', {
4807		errorMsg: Form.Validator.getMsg.pass('currencyDollar'),
4808		test: function(element){
4809			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'));
4810		}
4811	}],
4812
4813	['validate-one-required', {
4814		errorMsg: Form.Validator.getMsg.pass('oneRequired'),
4815		test: function(element, props){
4816			var p = document.id(props['validate-one-required']) || element.getParent(props['validate-one-required']);
4817			return p.getElements('input').some(function(el){
4818				if (['checkbox', 'radio'].contains(el.get('type'))) return el.get('checked');
4819				return el.get('value');
4820			});
4821		}
4822	}]
4823
4824]);
4825
4826Element.Properties.validator = {
4827
4828	set: function(options){
4829		this.get('validator').setOptions(options);
4830	},
4831
4832	get: function(){
4833		var validator = this.retrieve('validator');
4834		if (!validator){
4835			validator = new Form.Validator(this);
4836			this.store('validator', validator);
4837		}
4838		return validator;
4839	}
4840
4841};
4842
4843Element.implement({
4844
4845	validate: function(options){
4846		if (options) this.set('validator', options);
4847		return this.get('validator').validate();
4848	}
4849
4850});
4851
4852
4853
4854
4855
4856
4857
4858/*
4859---
4860
4861script: Form.Validator.Inline.js
4862
4863name: Form.Validator.Inline
4864
4865description: Extends Form.Validator to add inline messages.
4866
4867license: MIT-style license
4868
4869authors:
4870  - Aaron Newton
4871
4872requires:
4873  - /Form.Validator
4874
4875provides: [Form.Validator.Inline]
4876
4877...
4878*/
4879
4880Form.Validator.Inline = new Class({
4881
4882	Extends: Form.Validator,
4883
4884	options: {
4885		showError: function(errorElement){
4886			if (errorElement.reveal) errorElement.reveal();
4887			else errorElement.setStyle('display', 'block');
4888		},
4889		hideError: function(errorElement){
4890			if (errorElement.dissolve) errorElement.dissolve();
4891			else errorElement.setStyle('display', 'none');
4892		},
4893		scrollToErrorsOnSubmit: true,
4894		scrollToErrorsOnBlur: false,
4895		scrollToErrorsOnChange: false,
4896		scrollFxOptions: {
4897			transition: 'quad:out',
4898			offset: {
4899				y: -20
4900			}
4901		}
4902	},
4903
4904	initialize: function(form, options){
4905		this.parent(form, options);
4906		this.addEvent('onElementValidate', function(isValid, field, className, warn){
4907			var validator = this.getValidator(className);
4908			if (!isValid && validator.getError(field)){
4909				if (warn) field.addClass('warning');
4910				var advice = this.makeAdvice(className, field, validator.getError(field), warn);
4911				this.insertAdvice(advice, field);
4912				this.showAdvice(className, field);
4913			} else {
4914				this.hideAdvice(className, field);
4915			}
4916		});
4917	},
4918
4919	makeAdvice: function(className, field, error, warn){
4920		var errorMsg = (warn) ? this.warningPrefix : this.errorPrefix;
4921			errorMsg += (this.options.useTitles) ? field.title || error:error;
4922		var cssClass = (warn) ? 'warning-advice' : 'validation-advice';
4923		var advice = this.getAdvice(className, field);
4924		if (advice){
4925			advice = advice.set('html', errorMsg);
4926		} else {
4927			advice = new Element('div', {
4928				html: errorMsg,
4929				styles: { display: 'none' },
4930				id: 'advice-' + className.split(':')[0] + '-' + this.getFieldId(field)
4931			}).addClass(cssClass);
4932		}
4933		field.store('$moo:advice-' + className, advice);
4934		return advice;
4935	},
4936
4937	getFieldId : function(field){
4938		return field.id ? field.id : field.id = 'input_' + field.name;
4939	},
4940
4941	showAdvice: function(className, field){
4942		var advice = this.getAdvice(className, field);
4943		if (
4944			advice &&
4945			!field.retrieve('$moo:' + this.getPropName(className)) &&
4946			(
4947				advice.getStyle('display') == 'none' ||
4948				advice.getStyle('visiblity') == 'hidden' ||
4949				advice.getStyle('opacity') == 0
4950			)
4951		){
4952			field.store('$moo:' + this.getPropName(className), true);
4953			this.options.showError(advice);
4954			this.fireEvent('showAdvice', [field, advice, className]);
4955		}
4956	},
4957
4958	hideAdvice: function(className, field){
4959		var advice = this.getAdvice(className, field);
4960		if (advice && field.retrieve('$moo:' + this.getPropName(className))){
4961			field.store('$moo:' + this.getPropName(className), false);
4962			this.options.hideError(advice);
4963			this.fireEvent('hideAdvice', [field, advice, className]);
4964		}
4965	},
4966
4967	getPropName: function(className){
4968		return 'advice' + className;
4969	},
4970
4971	resetField: function(field){
4972		field = document.id(field);
4973		if (!field) return this;
4974		this.parent(field);
4975		field.get('validators').each(function(className){
4976			this.hideAdvice(className, field);
4977		}, this);
4978		return this;
4979	},
4980
4981	getAllAdviceMessages: function(field, force){
4982		var advice = [];
4983		if (field.hasClass('ignoreValidation') && !force) return advice;
4984		var validators = field.get('validators').some(function(cn){
4985			var warner = cn.test('^warn-') || field.hasClass('warnOnly');
4986			if (warner) cn = cn.replace(/^warn-/, '');
4987			var validator = this.getValidator(cn);
4988			if (!validator) return;
4989			advice.push({
4990				message: validator.getError(field),
4991				warnOnly: warner,
4992				passed: validator.test(),
4993				validator: validator
4994			});
4995		}, this);
4996		return advice;
4997	},
4998
4999	getAdvice: function(className, field){
5000		return field.retrieve('$moo:advice-' + className);
5001	},
5002
5003	insertAdvice: function(advice, field){
5004		//Check for error position prop
5005		var props = field.get('validatorProps');
5006		//Build advice
5007		if (!props.msgPos || !document.id(props.msgPos)){
5008			if (field.type && field.type.toLowerCase() == 'radio') field.getParent().adopt(advice);
5009			else advice.inject(document.id(field), 'after');
5010		} else {
5011			document.id(props.msgPos).grab(advice);
5012		}
5013	},
5014
5015	validateField: function(field, force, scroll){
5016		var result = this.parent(field, force);
5017		if (((this.options.scrollToErrorsOnSubmit && scroll == null) || scroll) && !result){
5018			var failed = document.id(this).getElement('.validation-failed');
5019			var par = document.id(this).getParent();
5020			while (par != document.body && par.getScrollSize().y == par.getSize().y){
5021				par = par.getParent();
5022			}
5023			var fx = par.retrieve('$moo:fvScroller');
5024			if (!fx && window.Fx && Fx.Scroll){
5025				fx = new Fx.Scroll(par, this.options.scrollFxOptions);
5026				par.store('$moo:fvScroller', fx);
5027			}
5028			if (failed){
5029				if (fx) fx.toElement(failed);
5030				else par.scrollTo(par.getScroll().x, failed.getPosition(par).y - 20);
5031			}
5032		}
5033		return result;
5034	},
5035
5036	watchFields: function(fields){
5037		fields.each(function(el){
5038		if (this.options.evaluateFieldsOnBlur){
5039			el.addEvent('blur', this.validationMonitor.pass([el, false, this.options.scrollToErrorsOnBlur], this));
5040		}
5041		if (this.options.evaluateFieldsOnChange){
5042				el.addEvent('change', this.validationMonitor.pass([el, true, this.options.scrollToErrorsOnChange], this));
5043			}
5044		}, this);
5045	}
5046
5047});
5048
5049
5050/*
5051---
5052
5053script: Form.Validator.Extras.js
5054
5055name: Form.Validator.Extras
5056
5057description: Additional validators for the Form.Validator class.
5058
5059license: MIT-style license
5060
5061authors:
5062  - Aaron Newton
5063
5064requires:
5065  - /Form.Validator
5066
5067provides: [Form.Validator.Extras]
5068
5069...
5070*/
5071Form.Validator.addAllThese([
5072
5073	['validate-enforce-oncheck', {
5074		test: function(element, props){
5075			var fv = element.getParent('form').retrieve('validator');
5076			if (!fv) return true;
5077			(props.toEnforce || document.id(props.enforceChildrenOf).getElements('input, select, textarea')).map(function(item){
5078				if (element.checked){
5079					fv.enforceField(item);
5080				} else {
5081					fv.ignoreField(item);
5082					fv.resetField(item);
5083				}
5084			});
5085			return true;
5086		}
5087	}],
5088
5089	['validate-ignore-oncheck', {
5090		test: function(element, props){
5091			var fv = element.getParent('form').retrieve('validator');
5092			if (!fv) return true;
5093			(props.toIgnore || document.id(props.ignoreChildrenOf).getElements('input, select, textarea')).each(function(item){
5094				if (element.checked){
5095					fv.ignoreField(item);
5096					fv.resetField(item);
5097				} else {
5098					fv.enforceField(item);
5099				}
5100			});
5101			return true;
5102		}
5103	}],
5104
5105	['validate-nospace', {
5106		errorMsg: function(){
5107			return Form.Validator.getMsg('noSpace');
5108		},
5109		test: function(element, props){
5110			return !element.get('value').test(/\s/);
5111		}
5112	}],
5113
5114	['validate-toggle-oncheck', {
5115		test: function(element, props){
5116			var fv = element.getParent('form').retrieve('validator');
5117			if (!fv) return true;
5118			var eleArr = props.toToggle || document.id(props.toToggleChildrenOf).getElements('input, select, textarea');
5119			if (!element.checked){
5120				eleArr.each(function(item){
5121					fv.ignoreField(item);
5122					fv.resetField(item);
5123				});
5124			} else {
5125				eleArr.each(function(item){
5126					fv.enforceField(item);
5127				});
5128			}
5129			return true;
5130		}
5131	}],
5132
5133	['validate-reqchk-bynode', {
5134		errorMsg: function(){
5135			return Form.Validator.getMsg('reqChkByNode');
5136		},
5137		test: function(element, props){
5138			return (document.id(props.nodeId).getElements(props.selector || 'input[type=checkbox], input[type=radio]')).some(function(item){
5139				return item.checked;
5140			});
5141		}
5142	}],
5143
5144	['validate-required-check', {
5145		errorMsg: function(element, props){
5146			return props.useTitle ? element.get('title') : Form.Validator.getMsg('requiredChk');
5147		},
5148		test: function(element, props){
5149			return !!element.checked;
5150		}
5151	}],
5152
5153	['validate-reqchk-byname', {
5154		errorMsg: function(element, props){
5155			return Form.Validator.getMsg('reqChkByName').substitute({label: props.label || element.get('type')});
5156		},
5157		test: function(element, props){
5158			var grpName = props.groupName || element.get('name');
5159			var oneCheckedItem = $$(document.getElementsByName(grpName)).some(function(item, index){
5160				return item.checked;
5161			});
5162			var fv = element.getParent('form').retrieve('validator');
5163			if (oneCheckedItem && fv) fv.resetField(element);
5164			return oneCheckedItem;
5165		}
5166	}],
5167
5168	['validate-match', {
5169		errorMsg: function(element, props){
5170			return Form.Validator.getMsg('match').substitute({matchName: props.matchName || document.id(props.matchInput).get('name')});
5171		},
5172		test: function(element, props){
5173			var eleVal = element.get('value');
5174			var matchVal = document.id(props.matchInput) && document.id(props.matchInput).get('value');
5175			return eleVal && matchVal ? eleVal == matchVal : true;
5176		}
5177	}],
5178
5179	['validate-after-date', {
5180		errorMsg: function(element, props){
5181			return Form.Validator.getMsg('afterDate').substitute({
5182				label: props.afterLabel || (props.afterElement ? Form.Validator.getMsg('startDate') : Form.Validator.getMsg('currentDate'))
5183			});
5184		},
5185		test: function(element, props){
5186			var start = document.id(props.afterElement) ? Date.parse(document.id(props.afterElement).get('value')) : new Date();
5187			var end = Date.parse(element.get('value'));
5188			return end && start ? end >= start : true;
5189		}
5190	}],
5191
5192	['validate-before-date', {
5193		errorMsg: function(element, props){
5194			return Form.Validator.getMsg('beforeDate').substitute({
5195				label: props.beforeLabel || (props.beforeElement ? Form.Validator.getMsg('endDate') : Form.Validator.getMsg('currentDate'))
5196			});
5197		},
5198		test: function(element, props){
5199			var start = Date.parse(element.get('value'));
5200			var end = document.id(props.beforeElement) ? Date.parse(document.id(props.beforeElement).get('value')) : new Date();
5201			return end && start ? end >= start : true;
5202		}
5203	}],
5204
5205	['validate-custom-required', {
5206		errorMsg: function(){
5207			return Form.Validator.getMsg('required');
5208		},
5209		test: function(element, props){
5210			return element.get('value') != props.emptyValue;
5211		}
5212	}],
5213
5214	['validate-same-month', {
5215		errorMsg: function(element, props){
5216			var startMo = document.id(props.sameMonthAs) && document.id(props.sameMonthAs).get('value');
5217			var eleVal = element.get('value');
5218			if (eleVal != '') return Form.Validator.getMsg(startMo ? 'sameMonth' : 'startMonth');
5219		},
5220		test: function(element, props){
5221			var d1 = Date.parse(element.get('value'));
5222			var d2 = Date.parse(document.id(props.sameMonthAs) && document.id(props.sameMonthAs).get('value'));
5223			return d1 && d2 ? d1.format('%B') == d2.format('%B') : true;
5224		}
5225	}],
5226
5227
5228	['validate-cc-num', {
5229		errorMsg: function(element){
5230			var ccNum = element.get('value').replace(/[^0-9]/g, '');
5231			return Form.Validator.getMsg('creditcard').substitute({length: ccNum.length});
5232		},
5233		test: function(element){
5234			// required is a different test
5235			if (Form.Validator.getValidator('IsEmpty').test(element)) return true;
5236
5237			// Clean number value
5238			var ccNum = element.get('value');
5239			ccNum = ccNum.replace(/[^0-9]/g, '');
5240
5241			var valid_type = false;
5242
5243			if (ccNum.test(/^4[0-9]{12}([0-9]{3})?$/)) valid_type = 'Visa';
5244			else if (ccNum.test(/^5[1-5]([0-9]{14})$/)) valid_type = 'Master Card';
5245			else if (ccNum.test(/^3[47][0-9]{13}$/)) valid_type = 'American Express';
5246			else if (ccNum.test(/^6011[0-9]{12}$/)) valid_type = 'Discover';
5247
5248			if (valid_type){
5249				var sum = 0;
5250				var cur = 0;
5251
5252				for (var i=ccNum.length-1; i>=0; --i){
5253					cur = ccNum.charAt(i).toInt();
5254					if (cur == 0) continue;
5255
5256					if ((ccNum.length-i) % 2 == 0) cur += cur;
5257					if (cur > 9){
5258						cur = cur.toString().charAt(0).toInt() + cur.toString().charAt(1).toInt();
5259					}
5260
5261					sum += cur;
5262				}
5263				if ((sum % 10) == 0) return true;
5264			}
5265
5266			var chunks = '';
5267			while (ccNum != ''){
5268				chunks += ' ' + ccNum.substr(0,4);
5269				ccNum = ccNum.substr(4);
5270			}
5271
5272			element.getParent('form').retrieve('validator').ignoreField(element);
5273			element.set('value', chunks.clean());
5274			element.getParent('form').retrieve('validator').enforceField(element);
5275			return false;
5276		}
5277	}]
5278
5279
5280]);
5281
5282
5283/*
5284---
5285
5286script: OverText.js
5287
5288name: OverText
5289
5290description: Shows text over an input that disappears when the user clicks into it. The text remains hidden if the user adds a value.
5291
5292license: MIT-style license
5293
5294authors:
5295  - Aaron Newton
5296
5297requires:
5298  - Core/Options
5299  - Core/Events
5300  - Core/Element.Event
5301  - Class.Binds
5302  - Class.Occlude
5303  - Element.Position
5304  - Element.Shortcuts
5305
5306provides: [OverText]
5307
5308...
5309*/
5310
5311var OverText = new Class({
5312
5313	Implements: [Options, Events, Class.Occlude],
5314
5315	Binds: ['reposition', 'assert', 'focus', 'hide'],
5316
5317	options: {/*
5318		textOverride: null,
5319		onFocus: function(){},
5320		onTextHide: function(textEl, inputEl){},
5321		onTextShow: function(textEl, inputEl){}, */
5322		element: 'label',
5323		labelClass: 'overTxtLabel',
5324		positionOptions: {
5325			position: 'upperLeft',
5326			edge: 'upperLeft',
5327			offset: {
5328				x: 4,
5329				y: 2
5330			}
5331		},
5332		poll: false,
5333		pollInterval: 250,
5334		wrap: false
5335	},
5336
5337	property: 'OverText',
5338
5339	initialize: function(element, options){
5340		element = this.element = document.id(element);
5341
5342		if (this.occlude()) return this.occluded;
5343		this.setOptions(options);
5344
5345		this.attach(element);
5346		OverText.instances.push(this);
5347
5348		if (this.options.poll) this.poll();
5349	},
5350
5351	toElement: function(){
5352		return this.element;
5353	},
5354
5355	attach: function(){
5356		var element = this.element,
5357			options = this.options,
5358			value = options.textOverride || element.get('alt') || element.get('title');
5359
5360		if (!value) return this;
5361
5362		var text = this.text = new Element(options.element, {
5363			'class': options.labelClass,
5364			styles: {
5365				lineHeight: 'normal',
5366				position: 'absolute',
5367				cursor: 'text'
5368			},
5369			html: value,
5370			events: {
5371				click: this.hide.pass(options.element == 'label', this)
5372			}
5373		}).inject(element, 'after');
5374
5375		if (options.element == 'label'){
5376			if (!element.get('id')) element.set('id', 'input_' + String.uniqueID());
5377			text.set('for', element.get('id'));
5378		}
5379
5380		if (options.wrap){
5381			this.textHolder = new Element('div.overTxtWrapper', {
5382				styles: {
5383					lineHeight: 'normal',
5384					position: 'relative'
5385				}
5386			}).grab(text).inject(element, 'before');
5387		}
5388
5389		return this.enable();
5390	},
5391
5392	destroy: function(){
5393		this.element.eliminate(this.property); // Class.Occlude storage
5394		this.disable();
5395		if (this.text) this.text.destroy();
5396		if (this.textHolder) this.textHolder.destroy();
5397		return this;
5398	},
5399
5400	disable: function(){
5401		this.element.removeEvents({
5402			focus: this.focus,
5403			blur: this.assert,
5404			change: this.assert
5405		});
5406		window.removeEvent('resize', this.reposition);
5407		this.hide(true, true);
5408		return this;
5409	},
5410
5411	enable: function(){
5412		this.element.addEvents({
5413			focus: this.focus,
5414			blur: this.assert,
5415			change: this.assert
5416		});
5417		window.addEvent('resize', this.reposition);
5418		this.reposition();
5419		return this;
5420	},
5421
5422	wrap: function(){
5423		if (this.options.element == 'label'){
5424			if (!this.element.get('id')) this.element.set('id', 'input_' + String.uniqueID());
5425			this.text.set('for', this.element.get('id'));
5426		}
5427	},
5428
5429	startPolling: function(){
5430		this.pollingPaused = false;
5431		return this.poll();
5432	},
5433
5434	poll: function(stop){
5435		//start immediately
5436		//pause on focus
5437		//resumeon blur
5438		if (this.poller && !stop) return this;
5439		if (stop){
5440			clearInterval(this.poller);
5441		} else {
5442			this.poller = (function(){
5443				if (!this.pollingPaused) this.assert(true);
5444			}).periodical(this.options.pollInterval, this);
5445		}
5446
5447		return this;
5448	},
5449
5450	stopPolling: function(){
5451		this.pollingPaused = true;
5452		return this.poll(true);
5453	},
5454
5455	focus: function(){
5456		if (this.text && (!this.text.isDisplayed() || this.element.get('disabled'))) return this;
5457		return this.hide();
5458	},
5459
5460	hide: function(suppressFocus, force){
5461		if (this.text && (this.text.isDisplayed() && (!this.element.get('disabled') || force))){
5462			this.text.hide();
5463			this.fireEvent('textHide', [this.text, this.element]);
5464			this.pollingPaused = true;
5465			if (!suppressFocus){
5466				try {
5467					this.element.fireEvent('focus');
5468					this.element.focus();
5469				} catch(e){} //IE barfs if you call focus on hidden elements
5470			}
5471		}
5472		return this;
5473	},
5474
5475	show: function(){
5476		if (this.text && !this.text.isDisplayed()){
5477			this.text.show();
5478			this.reposition();
5479			this.fireEvent('textShow', [this.text, this.element]);
5480			this.pollingPaused = false;
5481		}
5482		return this;
5483	},
5484
5485	test: function(){
5486		return !this.element.get('value');
5487	},
5488
5489	assert: function(suppressFocus){
5490		return this[this.test() ? 'show' : 'hide'](suppressFocus);
5491	},
5492
5493	reposition: function(){
5494		this.assert(true);
5495		if (!this.element.isVisible()) return this.stopPolling().hide();
5496		if (this.text && this.test()){
5497			this.text.position(Object.merge(this.options.positionOptions, {
5498				relativeTo: this.element
5499			}));
5500		}
5501		return this;
5502	}
5503
5504});
5505
5506OverText.instances = [];
5507
5508Object.append(OverText, {
5509
5510	each: function(fn){
5511		return OverText.instances.each(function(ot, i){
5512			if (ot.element && ot.text) fn.call(OverText, ot, i);
5513		});
5514	},
5515
5516	update: function(){
5517
5518		return OverText.each(function(ot){
5519			return ot.reposition();
5520		});
5521
5522	},
5523
5524	hideAll: function(){
5525
5526		return OverText.each(function(ot){
5527			return ot.hide(true, true);
5528		});
5529
5530	},
5531
5532	showAll: function(){
5533		return OverText.each(function(ot){
5534			return ot.show();
5535		});
5536	}
5537
5538});
5539
5540
5541
5542/*
5543---
5544
5545script: Fx.Elements.js
5546
5547name: Fx.Elements
5548
5549description: Effect to change any number of CSS properties of any number of Elements.
5550
5551license: MIT-style license
5552
5553authors:
5554  - Valerio Proietti
5555
5556requires:
5557  - Core/Fx.CSS
5558  - /MooTools.More
5559
5560provides: [Fx.Elements]
5561
5562...
5563*/
5564
5565Fx.Elements = new Class({
5566
5567	Extends: Fx.CSS,
5568
5569	initialize: function(elements, options){
5570		this.elements = this.subject = $$(elements);
5571		this.parent(options);
5572	},
5573
5574	compute: function(from, to, delta){
5575		var now = {};
5576
5577		for (var i in from){
5578			var iFrom = from[i], iTo = to[i], iNow = now[i] = {};
5579			for (var p in iFrom) iNow[p] = this.parent(iFrom[p], iTo[p], delta);
5580		}
5581
5582		return now;
5583	},
5584
5585	set: function(now){
5586		for (var i in now){
5587			if (!this.elements[i]) continue;
5588
5589			var iNow = now[i];
5590			for (var p in iNow) this.render(this.elements[i], p, iNow[p], this.options.unit);
5591		}
5592
5593		return this;
5594	},
5595
5596	start: function(obj){
5597		if (!this.check(obj)) return this;
5598		var from = {}, to = {};
5599
5600		for (var i in obj){
5601			if (!this.elements[i]) continue;
5602
5603			var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {};
5604
5605			for (var p in iProps){
5606				var parsed = this.prepare(this.elements[i], p, iProps[p]);
5607				iFrom[p] = parsed.from;
5608				iTo[p] = parsed.to;
5609			}
5610		}
5611
5612		return this.parent(from, to);
5613	}
5614
5615});
5616
5617
5618/*
5619---
5620
5621script: Fx.Accordion.js
5622
5623name: Fx.Accordion
5624
5625description: An Fx.Elements extension which allows you to easily create accordion type controls.
5626
5627license: MIT-style license
5628
5629authors:
5630  - Valerio Proietti
5631
5632requires:
5633  - Core/Element.Event
5634  - /Fx.Elements
5635
5636provides: [Fx.Accordion]
5637
5638...
5639*/
5640
5641Fx.Accordion = new Class({
5642
5643	Extends: Fx.Elements,
5644
5645	options: {/*
5646		onActive: function(toggler, section){},
5647		onBackground: function(toggler, section){},*/
5648		fixedHeight: false,
5649		fixedWidth: false,
5650		display: 0,
5651		show: false,
5652		height: true,
5653		width: false,
5654		opacity: true,
5655		alwaysHide: false,
5656		trigger: 'click',
5657		initialDisplayFx: true,
5658		resetHeight: true
5659	},
5660
5661	initialize: function(){
5662		var defined = function(obj){
5663			return obj != null;
5664		};
5665
5666		var params = Array.link(arguments, {
5667			'container': Type.isElement, //deprecated
5668			'options': Type.isObject,
5669			'togglers': defined,
5670			'elements': defined
5671		});
5672		this.parent(params.elements, params.options);
5673
5674		var options = this.options,
5675			togglers = this.togglers = $$(params.togglers);
5676
5677		this.previous = -1;
5678		this.internalChain = new Chain();
5679
5680		if (options.alwaysHide) this.options.link = 'chain';
5681
5682		if (options.show || this.options.show === 0){
5683			options.display = false;
5684			this.previous = options.show;
5685		}
5686
5687		if (options.start){
5688			options.display = false;
5689			options.show = false;
5690		}
5691
5692		var effects = this.effects = {};
5693
5694		if (options.opacity) effects.opacity = 'fullOpacity';
5695		if (options.width) effects.width = options.fixedWidth ? 'fullWidth' : 'offsetWidth';
5696		if (options.height) effects.height = options.fixedHeight ? 'fullHeight' : 'scrollHeight';
5697
5698		for (var i = 0, l = togglers.length; i < l; i++) this.addSection(togglers[i], this.elements[i]);
5699
5700		this.elements.each(function(el, i){
5701			if (options.show === i){
5702				this.fireEvent('active', [togglers[i], el]);
5703			} else {
5704				for (var fx in effects) el.setStyle(fx, 0);
5705			}
5706		}, this);
5707
5708		if (options.display || options.display === 0 || options.initialDisplayFx === false){
5709			this.display(options.display, options.initialDisplayFx);
5710		}
5711
5712		if (options.fixedHeight !== false) options.resetHeight = false;
5713		this.addEvent('complete', this.internalChain.callChain.bind(this.internalChain));
5714	},
5715
5716	addSection: function(toggler, element){
5717		toggler = document.id(toggler);
5718		element = document.id(element);
5719		this.togglers.include(toggler);
5720		this.elements.include(element);
5721
5722		var togglers = this.togglers,
5723			options = this.options,
5724			test = togglers.contains(toggler),
5725			idx = togglers.indexOf(toggler),
5726			displayer = this.display.pass(idx, this);
5727
5728		toggler.store('accordion:display', displayer)
5729			.addEvent(options.trigger, displayer);
5730
5731		if (options.height) element.setStyles({'padding-top': 0, 'border-top': 'none', 'padding-bottom': 0, 'border-bottom': 'none'});
5732		if (options.width) element.setStyles({'padding-left': 0, 'border-left': 'none', 'padding-right': 0, 'border-right': 'none'});
5733
5734		element.fullOpacity = 1;
5735		if (options.fixedWidth) element.fullWidth = options.fixedWidth;
5736		if (options.fixedHeight) element.fullHeight = options.fixedHeight;
5737		element.setStyle('overflow', 'hidden');
5738
5739		if (!test) for (var fx in this.effects){
5740			element.setStyle(fx, 0);
5741		}
5742		return this;
5743	},
5744
5745	removeSection: function(toggler, displayIndex){
5746		var togglers = this.togglers,
5747			idx = togglers.indexOf(toggler),
5748			element = this.elements[idx];
5749
5750		var remover = function(){
5751			togglers.erase(toggler);
5752			this.elements.erase(element);
5753			this.detach(toggler);
5754		}.bind(this);
5755
5756		if (this.now == idx || displayIndex != null){
5757			this.display(displayIndex != null ? displayIndex : (idx - 1 >= 0 ? idx - 1 : 0)).chain(remover);
5758		} else {
5759			remover();
5760		}
5761		return this;
5762	},
5763
5764	detach: function(toggler){
5765		var remove = function(toggler){
5766			toggler.removeEvent(this.options.trigger, toggler.retrieve('accordion:display'));
5767		}.bind(this);
5768
5769		if (!toggler) this.togglers.each(remove);
5770		else remove(toggler);
5771		return this;
5772	},
5773
5774	display: function(index, useFx){
5775		if (!this.check(index, useFx)) return this;
5776
5777		var obj = {},
5778			elements = this.elements,
5779			options = this.options,
5780			effects = this.effects;
5781
5782		if (useFx == null) useFx = true;
5783		if (typeOf(index) == 'element') index = elements.indexOf(index);
5784		if (index == this.previous && !options.alwaysHide) return this;
5785
5786		if (options.resetHeight){
5787			var prev = elements[this.previous];
5788			if (prev && !this.selfHidden){
5789				for (var fx in effects) prev.setStyle(fx, prev[effects[fx]]);
5790			}
5791		}
5792
5793		if ((this.timer && options.link == 'chain') || (index === this.previous && !options.alwaysHide)) return this;
5794
5795		this.previous = index;
5796		this.selfHidden = false;
5797
5798		elements.each(function(el, i){
5799			obj[i] = {};
5800			var hide;
5801			if (i != index){
5802				hide = true;
5803			} else if (options.alwaysHide && ((el.offsetHeight > 0 && options.height) || el.offsetWidth > 0 && options.width)){
5804				hide = true;
5805				this.selfHidden = true;
5806			}
5807			this.fireEvent(hide ? 'background' : 'active', [this.togglers[i], el]);
5808			for (var fx in effects) obj[i][fx] = hide ? 0 : el[effects[fx]];
5809			if (!useFx && !hide && options.resetHeight) obj[i].height = 'auto';
5810		}, this);
5811
5812		this.internalChain.clearChain();
5813		this.internalChain.chain(function(){
5814			if (options.resetHeight && !this.selfHidden){
5815				var el = elements[index];
5816				if (el) el.setStyle('height', 'auto');
5817			}
5818		}.bind(this));
5819
5820		return useFx ? this.start(obj) : this.set(obj).internalChain.callChain();
5821	}
5822
5823});
5824
5825
5826
5827
5828/*
5829---
5830
5831script: Fx.Move.js
5832
5833name: Fx.Move
5834
5835description: Defines Fx.Move, a class that works with Element.Position.js to transition an element from one location to another.
5836
5837license: MIT-style license
5838
5839authors:
5840  - Aaron Newton
5841
5842requires:
5843  - Core/Fx.Morph
5844  - /Element.Position
5845
5846provides: [Fx.Move]
5847
5848...
5849*/
5850
5851Fx.Move = new Class({
5852
5853	Extends: Fx.Morph,
5854
5855	options: {
5856		relativeTo: document.body,
5857		position: 'center',
5858		edge: false,
5859		offset: {x: 0, y: 0}
5860	},
5861
5862	start: function(destination){
5863		var element = this.element,
5864			topLeft = element.getStyles('top', 'left');
5865		if (topLeft.top == 'auto' || topLeft.left == 'auto'){
5866			element.setPosition(element.getPosition(element.getOffsetParent()));
5867		}
5868		return this.parent(element.position(Object.merge({}, this.options, destination, {returnPos: true})));
5869	}
5870
5871});
5872
5873Element.Properties.move = {
5874
5875	set: function(options){
5876		this.get('move').cancel().setOptions(options);
5877		return this;
5878	},
5879
5880	get: function(){
5881		var move = this.retrieve('move');
5882		if (!move){
5883			move = new Fx.Move(this, {link: 'cancel'});
5884			this.store('move', move);
5885		}
5886		return move;
5887	}
5888
5889};
5890
5891Element.implement({
5892
5893	move: function(options){
5894		this.get('move').start(options);
5895		return this;
5896	}
5897
5898});
5899
5900
5901/*
5902---
5903
5904script: Fx.Scroll.js
5905
5906name: Fx.Scroll
5907
5908description: Effect to smoothly scroll any element, including the window.
5909
5910license: MIT-style license
5911
5912authors:
5913  - Valerio Proietti
5914
5915requires:
5916  - Core/Fx
5917  - Core/Element.Event
5918  - Core/Element.Dimensions
5919  - /MooTools.More
5920
5921provides: [Fx.Scroll]
5922
5923...
5924*/
5925
5926(function(){
5927
5928Fx.Scroll = new Class({
5929
5930	Extends: Fx,
5931
5932	options: {
5933		offset: {x: 0, y: 0},
5934		wheelStops: true
5935	},
5936
5937	initialize: function(element, options){
5938		this.element = this.subject = document.id(element);
5939		this.parent(options);
5940
5941		if (typeOf(this.element) != 'element') this.element = document.id(this.element.getDocument().body);
5942
5943		if (this.options.wheelStops){
5944			var stopper = this.element,
5945				cancel = this.cancel.pass(false, this);
5946			this.addEvent('start', function(){
5947				stopper.addEvent('mousewheel', cancel);
5948			}, true);
5949			this.addEvent('complete', function(){
5950				stopper.removeEvent('mousewheel', cancel);
5951			}, true);
5952		}
5953	},
5954
5955	set: function(){
5956		var now = Array.flatten(arguments);
5957		if (Browser.firefox) now = [Math.round(now[0]), Math.round(now[1])]; // not needed anymore in newer firefox versions
5958		this.element.scrollTo(now[0], now[1]);
5959		return this;
5960	},
5961
5962	compute: function(from, to, delta){
5963		return [0, 1].map(function(i){
5964			return Fx.compute(from[i], to[i], delta);
5965		});
5966	},
5967
5968	start: function(x, y){
5969		if (!this.check(x, y)) return this;
5970		var scroll = this.element.getScroll();
5971		return this.parent([scroll.x, scroll.y], [x, y]);
5972	},
5973
5974	calculateScroll: function(x, y){
5975		var element = this.element,
5976			scrollSize = element.getScrollSize(),
5977			scroll = element.getScroll(),
5978			size = element.getSize(),
5979			offset = this.options.offset,
5980			values = {x: x, y: y};
5981
5982		for (var z in values){
5983			if (!values[z] && values[z] !== 0) values[z] = scroll[z];
5984			if (typeOf(values[z]) != 'number') values[z] = scrollSize[z] - size[z];
5985			values[z] += offset[z];
5986		}
5987
5988		return [values.x, values.y];
5989	},
5990
5991	toTop: function(){
5992		return this.start.apply(this, this.calculateScroll(false, 0));
5993	},
5994
5995	toLeft: function(){
5996		return this.start.apply(this, this.calculateScroll(0, false));
5997	},
5998
5999	toRight: function(){
6000		return this.start.apply(this, this.calculateScroll('right', false));
6001	},
6002
6003	toBottom: function(){
6004		return this.start.apply(this, this.calculateScroll(false, 'bottom'));
6005	},
6006
6007	toElement: function(el, axes){
6008		axes = axes ? Array.from(axes) : ['x', 'y'];
6009		var scroll = isBody(this.element) ? {x: 0, y: 0} : this.element.getScroll();
6010		var position = Object.map(document.id(el).getPosition(this.element), function(value, axis){
6011			return axes.contains(axis) ? value + scroll[axis] : false;
6012		});
6013		return this.start.apply(this, this.calculateScroll(position.x, position.y));
6014	},
6015
6016	toElementEdge: function(el, axes, offset){
6017		axes = axes ? Array.from(axes) : ['x', 'y'];
6018		el = document.id(el);
6019		var to = {},
6020			position = el.getPosition(this.element),
6021			size = el.getSize(),
6022			scroll = this.element.getScroll(),
6023			containerSize = this.element.getSize(),
6024			edge = {
6025				x: position.x + size.x,
6026				y: position.y + size.y
6027			};
6028
6029		['x', 'y'].each(function(axis){
6030			if (axes.contains(axis)){
6031				if (edge[axis] > scroll[axis] + containerSize[axis]) to[axis] = edge[axis] - containerSize[axis];
6032				if (position[axis] < scroll[axis]) to[axis] = position[axis];
6033			}
6034			if (to[axis] == null) to[axis] = scroll[axis];
6035			if (offset && offset[axis]) to[axis] = to[axis] + offset[axis];
6036		}, this);
6037
6038		if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y);
6039		return this;
6040	},
6041
6042	toElementCenter: function(el, axes, offset){
6043		axes = axes ? Array.from(axes) : ['x', 'y'];
6044		el = document.id(el);
6045		var to = {},
6046			position = el.getPosition(this.element),
6047			size = el.getSize(),
6048			scroll = this.element.getScroll(),
6049			containerSize = this.element.getSize();
6050
6051		['x', 'y'].each(function(axis){
6052			if (axes.contains(axis)){
6053				to[axis] = position[axis] - (containerSize[axis] - size[axis]) / 2;
6054			}
6055			if (to[axis] == null) to[axis] = scroll[axis];
6056			if (offset && offset[axis]) to[axis] = to[axis] + offset[axis];
6057		}, this);
6058
6059		if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y);
6060		return this;
6061	}
6062
6063});
6064
6065
6066
6067function isBody(element){
6068	return (/^(?:body|html)$/i).test(element.tagName);
6069}
6070
6071})();
6072
6073
6074/*
6075---
6076
6077script: Fx.Slide.js
6078
6079name: Fx.Slide
6080
6081description: Effect to slide an element in and out of view.
6082
6083license: MIT-style license
6084
6085authors:
6086  - Valerio Proietti
6087
6088requires:
6089  - Core/Fx
6090  - Core/Element.Style
6091  - /MooTools.More
6092
6093provides: [Fx.Slide]
6094
6095...
6096*/
6097
6098Fx.Slide = new Class({
6099
6100	Extends: Fx,
6101
6102	options: {
6103		mode: 'vertical',
6104		wrapper: false,
6105		hideOverflow: true,
6106		resetHeight: false
6107	},
6108
6109	initialize: function(element, options){
6110		element = this.element = this.subject = document.id(element);
6111		this.parent(options);
6112		options = this.options;
6113
6114		var wrapper = element.retrieve('wrapper'),
6115			styles = element.getStyles('margin', 'position', 'overflow');
6116
6117		if (options.hideOverflow) styles = Object.append(styles, {overflow: 'hidden'});
6118		if (options.wrapper) wrapper = document.id(options.wrapper).setStyles(styles);
6119
6120		if (!wrapper) wrapper = new Element('div', {
6121			styles: styles
6122		}).wraps(element);
6123
6124		element.store('wrapper', wrapper).setStyle('margin', 0);
6125		if (element.getStyle('overflow') == 'visible') element.setStyle('overflow', 'hidden');
6126
6127		this.now = [];
6128		this.open = true;
6129		this.wrapper = wrapper;
6130
6131		this.addEvent('complete', function(){
6132			this.open = (wrapper['offset' + this.layout.capitalize()] != 0);
6133			if (this.open && this.options.resetHeight) wrapper.setStyle('height', '');
6134		}, true);
6135	},
6136
6137	vertical: function(){
6138		this.margin = 'margin-top';
6139		this.layout = 'height';
6140		this.offset = this.element.offsetHeight;
6141	},
6142
6143	horizontal: function(){
6144		this.margin = 'margin-left';
6145		this.layout = 'width';
6146		this.offset = this.element.offsetWidth;
6147	},
6148
6149	set: function(now){
6150		this.element.setStyle(this.margin, now[0]);
6151		this.wrapper.setStyle(this.layout, now[1]);
6152		return this;
6153	},
6154
6155	compute: function(from, to, delta){
6156		return [0, 1].map(function(i){
6157			return Fx.compute(from[i], to[i], delta);
6158		});
6159	},
6160
6161	start: function(how, mode){
6162		if (!this.check(how, mode)) return this;
6163		this[mode || this.options.mode]();
6164
6165		var margin = this.element.getStyle(this.margin).toInt(),
6166			layout = this.wrapper.getStyle(this.layout).toInt(),
6167			caseIn = [[margin, layout], [0, this.offset]],
6168			caseOut = [[margin, layout], [-this.offset, 0]],
6169			start;
6170
6171		switch (how){
6172			case 'in': start = caseIn; break;
6173			case 'out': start = caseOut; break;
6174			case 'toggle': start = (layout == 0) ? caseIn : caseOut;
6175		}
6176		return this.parent(start[0], start[1]);
6177	},
6178
6179	slideIn: function(mode){
6180		return this.start('in', mode);
6181	},
6182
6183	slideOut: function(mode){
6184		return this.start('out', mode);
6185	},
6186
6187	hide: function(mode){
6188		this[mode || this.options.mode]();
6189		this.open = false;
6190		return this.set([-this.offset, 0]);
6191	},
6192
6193	show: function(mode){
6194		this[mode || this.options.mode]();
6195		this.open = true;
6196		return this.set([0, this.offset]);
6197	},
6198
6199	toggle: function(mode){
6200		return this.start('toggle', mode);
6201	}
6202
6203});
6204
6205Element.Properties.slide = {
6206
6207	set: function(options){
6208		this.get('slide').cancel().setOptions(options);
6209		return this;
6210	},
6211
6212	get: function(){
6213		var slide = this.retrieve('slide');
6214		if (!slide){
6215			slide = new Fx.Slide(this, {link: 'cancel'});
6216			this.store('slide', slide);
6217		}
6218		return slide;
6219	}
6220
6221};
6222
6223Element.implement({
6224
6225	slide: function(how, mode){
6226		how = how || 'toggle';
6227		var slide = this.get('slide'), toggle;
6228		switch (how){
6229			case 'hide': slide.hide(mode); break;
6230			case 'show': slide.show(mode); break;
6231			case 'toggle':
6232				var flag = this.retrieve('slide:flag', slide.open);
6233				slide[flag ? 'slideOut' : 'slideIn'](mode);
6234				this.store('slide:flag', !flag);
6235				toggle = true;
6236			break;
6237			default: slide.start(how, mode);
6238		}
6239		if (!toggle) this.eliminate('slide:flag');
6240		return this;
6241	}
6242
6243});
6244
6245
6246/*
6247---
6248
6249script: Fx.SmoothScroll.js
6250
6251name: Fx.SmoothScroll
6252
6253description: Class for creating a smooth scrolling effect to all internal links on the page.
6254
6255license: MIT-style license
6256
6257authors:
6258  - Valerio Proietti
6259
6260requires:
6261  - Core/Slick.Finder
6262  - /Fx.Scroll
6263
6264provides: [Fx.SmoothScroll]
6265
6266...
6267*/
6268
6269Fx.SmoothScroll = new Class({
6270
6271	Extends: Fx.Scroll,
6272
6273	options: {
6274		axes: ['x', 'y']
6275	},
6276
6277	initialize: function(options, context){
6278		context = context || document;
6279		this.doc = context.getDocument();
6280		this.parent(this.doc, options);
6281
6282		var win = context.getWindow(),
6283			location = win.location.href.match(/^[^#]*/)[0] + '#',
6284			links = $$(this.options.links || this.doc.links);
6285
6286		links.each(function(link){
6287			if (link.href.indexOf(location) != 0) return;
6288			var anchor = link.href.substr(location.length);
6289			if (anchor) this.useLink(link, anchor);
6290		}, this);
6291
6292		this.addEvent('complete', function(){
6293			win.location.hash = this.anchor;
6294			this.element.scrollTo(this.to[0], this.to[1]);
6295		}, true);
6296	},
6297
6298	useLink: function(link, anchor){
6299
6300		link.addEvent('click', function(event){
6301			var el = document.id(anchor) || this.doc.getElement('a[name=' + anchor + ']');
6302			if (!el) return;
6303
6304			event.preventDefault();
6305			this.toElement(el, this.options.axes).chain(function(){
6306				this.fireEvent('scrolledTo', [link, el]);
6307			}.bind(this));
6308
6309			this.anchor = anchor;
6310
6311		}.bind(this));
6312
6313		return this;
6314	}
6315});
6316
6317
6318/*
6319---
6320
6321script: Fx.Sort.js
6322
6323name: Fx.Sort
6324
6325description: Defines Fx.Sort, a class that reorders lists with a transition.
6326
6327license: MIT-style license
6328
6329authors:
6330  - Aaron Newton
6331
6332requires:
6333  - Core/Element.Dimensions
6334  - /Fx.Elements
6335  - /Element.Measure
6336
6337provides: [Fx.Sort]
6338
6339...
6340*/
6341
6342Fx.Sort = new Class({
6343
6344	Extends: Fx.Elements,
6345
6346	options: {
6347		mode: 'vertical'
6348	},
6349
6350	initialize: function(elements, options){
6351		this.parent(elements, options);
6352		this.elements.each(function(el){
6353			if (el.getStyle('position') == 'static') el.setStyle('position', 'relative');
6354		});
6355		this.setDefaultOrder();
6356	},
6357
6358	setDefaultOrder: function(){
6359		this.currentOrder = this.elements.map(function(el, index){
6360			return index;
6361		});
6362	},
6363
6364	sort: function(){
6365		if (!this.check(arguments)) return this;
6366		var newOrder = Array.flatten(arguments);
6367
6368		var top = 0,
6369			left = 0,
6370			next = {},
6371			zero = {},
6372			vert = this.options.mode == 'vertical';
6373
6374		var current = this.elements.map(function(el, index){
6375			var size = el.getComputedSize({styles: ['border', 'padding', 'margin']});
6376			var val;
6377			if (vert){
6378				val = {
6379					top: top,
6380					margin: size['margin-top'],
6381					height: size.totalHeight
6382				};
6383				top += val.height - size['margin-top'];
6384			} else {
6385				val = {
6386					left: left,
6387					margin: size['margin-left'],
6388					width: size.totalWidth
6389				};
6390				left += val.width;
6391			}
6392			var plane = vert ? 'top' : 'left';
6393			zero[index] = {};
6394			var start = el.getStyle(plane).toInt();
6395			zero[index][plane] = start || 0;
6396			return val;
6397		}, this);
6398
6399		this.set(zero);
6400		newOrder = newOrder.map(function(i){ return i.toInt(); });
6401		if (newOrder.length != this.elements.length){
6402			this.currentOrder.each(function(index){
6403				if (!newOrder.contains(index)) newOrder.push(index);
6404			});
6405			if (newOrder.length > this.elements.length)
6406				newOrder.splice(this.elements.length-1, newOrder.length - this.elements.length);
6407		}
6408		var margin = 0;
6409		top = left = 0;
6410		newOrder.each(function(item){
6411			var newPos = {};
6412			if (vert){
6413				newPos.top = top - current[item].top - margin;
6414				top += current[item].height;
6415			} else {
6416				newPos.left = left - current[item].left;
6417				left += current[item].width;
6418			}
6419			margin = margin + current[item].margin;
6420			next[item]=newPos;
6421		}, this);
6422		var mapped = {};
6423		Array.clone(newOrder).sort().each(function(index){
6424			mapped[index] = next[index];
6425		});
6426		this.start(mapped);
6427		this.currentOrder = newOrder;
6428
6429		return this;
6430	},
6431
6432	rearrangeDOM: function(newOrder){
6433		newOrder = newOrder || this.currentOrder;
6434		var parent = this.elements[0].getParent();
6435		var rearranged = [];
6436		this.elements.setStyle('opacity', 0);
6437		//move each element and store the new default order
6438		newOrder.each(function(index){
6439			rearranged.push(this.elements[index].inject(parent).setStyles({
6440				top: 0,
6441				left: 0
6442			}));
6443		}, this);
6444		this.elements.setStyle('opacity', 1);
6445		this.elements = $$(rearranged);
6446		this.setDefaultOrder();
6447		return this;
6448	},
6449
6450	getDefaultOrder: function(){
6451		return this.elements.map(function(el, index){
6452			return index;
6453		});
6454	},
6455
6456	getCurrentOrder: function(){
6457		return this.currentOrder;
6458	},
6459
6460	forward: function(){
6461		return this.sort(this.getDefaultOrder());
6462	},
6463
6464	backward: function(){
6465		return this.sort(this.getDefaultOrder().reverse());
6466	},
6467
6468	reverse: function(){
6469		return this.sort(this.currentOrder.reverse());
6470	},
6471
6472	sortByElements: function(elements){
6473		return this.sort(elements.map(function(el){
6474			return this.elements.indexOf(el);
6475		}, this));
6476	},
6477
6478	swap: function(one, two){
6479		if (typeOf(one) == 'element') one = this.elements.indexOf(one);
6480		if (typeOf(two) == 'element') two = this.elements.indexOf(two);
6481
6482		var newOrder = Array.clone(this.currentOrder);
6483		newOrder[this.currentOrder.indexOf(one)] = two;
6484		newOrder[this.currentOrder.indexOf(two)] = one;
6485
6486		return this.sort(newOrder);
6487	}
6488
6489});
6490
6491
6492/*
6493---
6494
6495script: Drag.js
6496
6497name: Drag
6498
6499description: The base Drag Class. Can be used to drag and resize Elements using mouse events.
6500
6501license: MIT-style license
6502
6503authors:
6504  - Valerio Proietti
6505  - Tom Occhinno
6506  - Jan Kassens
6507
6508requires:
6509  - Core/Events
6510  - Core/Options
6511  - Core/Element.Event
6512  - Core/Element.Style
6513  - Core/Element.Dimensions
6514  - /MooTools.More
6515
6516provides: [Drag]
6517...
6518
6519*/
6520
6521var Drag = new Class({
6522
6523	Implements: [Events, Options],
6524
6525	options: {/*
6526		onBeforeStart: function(thisElement){},
6527		onStart: function(thisElement, event){},
6528		onSnap: function(thisElement){},
6529		onDrag: function(thisElement, event){},
6530		onCancel: function(thisElement){},
6531		onComplete: function(thisElement, event){},*/
6532		snap: 6,
6533		unit: 'px',
6534		grid: false,
6535		style: true,
6536		limit: false,
6537		handle: false,
6538		invert: false,
6539		preventDefault: false,
6540		stopPropagation: false,
6541		modifiers: {x: 'left', y: 'top'}
6542	},
6543
6544	initialize: function(){
6545		var params = Array.link(arguments, {
6546			'options': Type.isObject,
6547			'element': function(obj){
6548				return obj != null;
6549			}
6550		});
6551
6552		this.element = document.id(params.element);
6553		this.document = this.element.getDocument();
6554		this.setOptions(params.options || {});
6555		var htype = typeOf(this.options.handle);
6556		this.handles = ((htype == 'array' || htype == 'collection') ? $$(this.options.handle) : document.id(this.options.handle)) || this.element;
6557		this.mouse = {'now': {}, 'pos': {}};
6558		this.value = {'start': {}, 'now': {}};
6559
6560		this.selection = (Browser.ie) ? 'selectstart' : 'mousedown';
6561
6562
6563		if (Browser.ie && !Drag.ondragstartFixed){
6564			document.ondragstart = Function.from(false);
6565			Drag.ondragstartFixed = true;
6566		}
6567
6568		this.bound = {
6569			start: this.start.bind(this),
6570			check: this.check.bind(this),
6571			drag: this.drag.bind(this),
6572			stop: this.stop.bind(this),
6573			cancel: this.cancel.bind(this),
6574			eventStop: Function.from(false)
6575		};
6576		this.attach();
6577	},
6578
6579	attach: function(){
6580		this.handles.addEvent('mousedown', this.bound.start);
6581		return this;
6582	},
6583
6584	detach: function(){
6585		this.handles.removeEvent('mousedown', this.bound.start);
6586		return this;
6587	},
6588
6589	start: function(event){
6590		var options = this.options;
6591
6592		if (event.rightClick) return;
6593
6594		if (options.preventDefault) event.preventDefault();
6595		if (options.stopPropagation) event.stopPropagation();
6596		this.mouse.start = event.page;
6597
6598		this.fireEvent('beforeStart', this.element);
6599
6600		var limit = options.limit;
6601		this.limit = {x: [], y: []};
6602
6603		var z, coordinates;
6604		for (z in options.modifiers){
6605			if (!options.modifiers[z]) continue;
6606
6607			var style = this.element.getStyle(options.modifiers[z]);
6608
6609			// Some browsers (IE and Opera) don't always return pixels.
6610			if (style && !style.match(/px$/)){
6611				if (!coordinates) coordinates = this.element.getCoordinates(this.element.getOffsetParent());
6612				style = coordinates[options.modifiers[z]];
6613			}
6614
6615			if (options.style) this.value.now[z] = (style || 0).toInt();
6616			else this.value.now[z] = this.element[options.modifiers[z]];
6617
6618			if (options.invert) this.value.now[z] *= -1;
6619
6620			this.mouse.pos[z] = event.page[z] - this.value.now[z];
6621
6622			if (limit && limit[z]){
6623				var i = 2;
6624				while (i--){
6625					var limitZI = limit[z][i];
6626					if (limitZI || limitZI === 0) this.limit[z][i] = (typeof limitZI == 'function') ? limitZI() : limitZI;
6627				}
6628			}
6629		}
6630
6631		if (typeOf(this.options.grid) == 'number') this.options.grid = {
6632			x: this.options.grid,
6633			y: this.options.grid
6634		};
6635
6636		var events = {
6637			mousemove: this.bound.check,
6638			mouseup: this.bound.cancel
6639		};
6640		events[this.selection] = this.bound.eventStop;
6641		this.document.addEvents(events);
6642	},
6643
6644	check: function(event){
6645		if (this.options.preventDefault) event.preventDefault();
6646		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)));
6647		if (distance > this.options.snap){
6648			this.cancel();
6649			this.document.addEvents({
6650				mousemove: this.bound.drag,
6651				mouseup: this.bound.stop
6652			});
6653			this.fireEvent('start', [this.element, event]).fireEvent('snap', this.element);
6654		}
6655	},
6656
6657	drag: function(event){
6658		var options = this.options;
6659
6660		if (options.preventDefault) event.preventDefault();
6661		this.mouse.now = event.page;
6662
6663		for (var z in options.modifiers){
6664			if (!options.modifiers[z]) continue;
6665			this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z];
6666
6667			if (options.invert) this.value.now[z] *= -1;
6668
6669			if (options.limit && this.limit[z]){
6670				if ((this.limit[z][1] || this.limit[z][1] === 0) && (this.value.now[z] > this.limit[z][1])){
6671					this.value.now[z] = this.limit[z][1];
6672				} else if ((this.limit[z][0] || this.limit[z][0] === 0) && (this.value.now[z] < this.limit[z][0])){
6673					this.value.now[z] = this.limit[z][0];
6674				}
6675			}
6676
6677			if (options.grid[z]) this.value.now[z] -= ((this.value.now[z] - (this.limit[z][0]||0)) % options.grid[z]);
6678
6679			if (options.style) this.element.setStyle(options.modifiers[z], this.value.now[z] + options.unit);
6680			else this.element[options.modifiers[z]] = this.value.now[z];
6681		}
6682
6683		this.fireEvent('drag', [this.element, event]);
6684	},
6685
6686	cancel: function(event){
6687		this.document.removeEvents({
6688			mousemove: this.bound.check,
6689			mouseup: this.bound.cancel
6690		});
6691		if (event){
6692			this.document.removeEvent(this.selection, this.bound.eventStop);
6693			this.fireEvent('cancel', this.element);
6694		}
6695	},
6696
6697	stop: function(event){
6698		var events = {
6699			mousemove: this.bound.drag,
6700			mouseup: this.bound.stop
6701		};
6702		events[this.selection] = this.bound.eventStop;
6703		this.document.removeEvents(events);
6704		if (event) this.fireEvent('complete', [this.element, event]);
6705	}
6706
6707});
6708
6709Element.implement({
6710
6711	makeResizable: function(options){
6712		var drag = new Drag(this, Object.merge({
6713			modifiers: {
6714				x: 'width',
6715				y: 'height'
6716			}
6717		}, options));
6718
6719		this.store('resizer', drag);
6720		return drag.addEvent('drag', function(){
6721			this.fireEvent('resize', drag);
6722		}.bind(this));
6723	}
6724
6725});
6726
6727
6728/*
6729---
6730
6731script: Drag.Move.js
6732
6733name: Drag.Move
6734
6735description: A Drag extension that provides support for the constraining of draggables to containers and droppables.
6736
6737license: MIT-style license
6738
6739authors:
6740  - Valerio Proietti
6741  - Tom Occhinno
6742  - Jan Kassens
6743  - Aaron Newton
6744  - Scott Kyle
6745
6746requires:
6747  - Core/Element.Dimensions
6748  - /Drag
6749
6750provides: [Drag.Move]
6751
6752...
6753*/
6754
6755Drag.Move = new Class({
6756
6757	Extends: Drag,
6758
6759	options: {/*
6760		onEnter: function(thisElement, overed){},
6761		onLeave: function(thisElement, overed){},
6762		onDrop: function(thisElement, overed, event){},*/
6763		droppables: [],
6764		container: false,
6765		precalculate: false,
6766		includeMargins: true,
6767		checkDroppables: true
6768	},
6769
6770	initialize: function(element, options){
6771		this.parent(element, options);
6772		element = this.element;
6773
6774		this.droppables = $$(this.options.droppables);
6775		this.container = document.id(this.options.container);
6776
6777		if (this.container && typeOf(this.container) != 'element')
6778			this.container = document.id(this.container.getDocument().body);
6779
6780		if (this.options.style){
6781			if (this.options.modifiers.x == 'left' && this.options.modifiers.y == 'top'){
6782				var parent = element.getOffsetParent(),
6783					styles = element.getStyles('left', 'top');
6784				if (parent && (styles.left == 'auto' || styles.top == 'auto')){
6785					element.setPosition(element.getPosition(parent));
6786				}
6787			}
6788
6789			if (element.getStyle('position') == 'static') element.setStyle('position', 'absolute');
6790		}
6791
6792		this.addEvent('start', this.checkDroppables, true);
6793		this.overed = null;
6794	},
6795
6796	start: function(event){
6797		if (this.container) this.options.limit = this.calculateLimit();
6798
6799		if (this.options.precalculate){
6800			this.positions = this.droppables.map(function(el){
6801				return el.getCoordinates();
6802			});
6803		}
6804
6805		this.parent(event);
6806	},
6807
6808	calculateLimit: function(){
6809		var element = this.element,
6810			container = this.container,
6811
6812			offsetParent = document.id(element.getOffsetParent()) || document.body,
6813			containerCoordinates = container.getCoordinates(offsetParent),
6814			elementMargin = {},
6815			elementBorder = {},
6816			containerMargin = {},
6817			containerBorder = {},
6818			offsetParentPadding = {};
6819
6820		['top', 'right', 'bottom', 'left'].each(function(pad){
6821			elementMargin[pad] = element.getStyle('margin-' + pad).toInt();
6822			elementBorder[pad] = element.getStyle('border-' + pad).toInt();
6823			containerMargin[pad] = container.getStyle('margin-' + pad).toInt();
6824			containerBorder[pad] = container.getStyle('border-' + pad).toInt();
6825			offsetParentPadding[pad] = offsetParent.getStyle('padding-' + pad).toInt();
6826		}, this);
6827
6828		var width = element.offsetWidth + elementMargin.left + elementMargin.right,
6829			height = element.offsetHeight + elementMargin.top + elementMargin.bottom,
6830			left = 0,
6831			top = 0,
6832			right = containerCoordinates.right - containerBorder.right - width,
6833			bottom = containerCoordinates.bottom - containerBorder.bottom - height;
6834
6835		if (this.options.includeMargins){
6836			left += elementMargin.left;
6837			top += elementMargin.top;
6838		} else {
6839			right += elementMargin.right;
6840			bottom += elementMargin.bottom;
6841		}
6842
6843		if (element.getStyle('position') == 'relative'){
6844			var coords = element.getCoordinates(offsetParent);
6845			coords.left -= element.getStyle('left').toInt();
6846			coords.top -= element.getStyle('top').toInt();
6847
6848			left -= coords.left;
6849			top -= coords.top;
6850			if (container.getStyle('position') != 'relative'){
6851				left += containerBorder.left;
6852				top += containerBorder.top;
6853			}
6854			right += elementMargin.left - coords.left;
6855			bottom += elementMargin.top - coords.top;
6856
6857			if (container != offsetParent){
6858				left += containerMargin.left + offsetParentPadding.left;
6859				top += ((Browser.ie6 || Browser.ie7) ? 0 : containerMargin.top) + offsetParentPadding.top;
6860			}
6861		} else {
6862			left -= elementMargin.left;
6863			top -= elementMargin.top;
6864			if (container != offsetParent){
6865				left += containerCoordinates.left + containerBorder.left;
6866				top += containerCoordinates.top + containerBorder.top;
6867			}
6868		}
6869
6870		return {
6871			x: [left, right],
6872			y: [top, bottom]
6873		};
6874	},
6875
6876	getDroppableCoordinates: function(element){
6877		var position = element.getCoordinates();
6878		if (element.getStyle('position') == 'fixed'){
6879			var scroll = window.getScroll();
6880			position.left += scroll.x;
6881			position.right += scroll.x;
6882			position.top += scroll.y;
6883			position.bottom += scroll.y;
6884		}
6885		return position;
6886	},
6887
6888	checkDroppables: function(){
6889		var overed = this.droppables.filter(function(el, i){
6890			el = this.positions ? this.positions[i] : this.getDroppableCoordinates(el);
6891			var now = this.mouse.now;
6892			return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top);
6893		}, this).getLast();
6894
6895		if (this.overed != overed){
6896			if (this.overed) this.fireEvent('leave', [this.element, this.overed]);
6897			if (overed) this.fireEvent('enter', [this.element, overed]);
6898			this.overed = overed;
6899		}
6900	},
6901
6902	drag: function(event){
6903		this.parent(event);
6904		if (this.options.checkDroppables && this.droppables.length) this.checkDroppables();
6905	},
6906
6907	stop: function(event){
6908		this.checkDroppables();
6909		this.fireEvent('drop', [this.element, this.overed, event]);
6910		this.overed = null;
6911		return this.parent(event);
6912	}
6913
6914});
6915
6916Element.implement({
6917
6918	makeDraggable: function(options){
6919		var drag = new Drag.Move(this, options);
6920		this.store('dragger', drag);
6921		return drag;
6922	}
6923
6924});
6925
6926
6927/*
6928---
6929
6930script: Slider.js
6931
6932name: Slider
6933
6934description: Class for creating horizontal and vertical slider controls.
6935
6936license: MIT-style license
6937
6938authors:
6939  - Valerio Proietti
6940
6941requires:
6942  - Core/Element.Dimensions
6943  - /Class.Binds
6944  - /Drag
6945  - /Element.Measure
6946
6947provides: [Slider]
6948
6949...
6950*/
6951
6952var Slider = new Class({
6953
6954	Implements: [Events, Options],
6955
6956	Binds: ['clickedElement', 'draggedKnob', 'scrolledElement'],
6957
6958	options: {/*
6959		onTick: function(intPosition){},
6960		onChange: function(intStep){},
6961		onComplete: function(strStep){},*/
6962		onTick: function(position){
6963			this.setKnobPosition(position);
6964		},
6965		initialStep: 0,
6966		snap: false,
6967		offset: 0,
6968		range: false,
6969		wheel: false,
6970		steps: 100,
6971		mode: 'horizontal'
6972	},
6973
6974	initialize: function(element, knob, options){
6975		this.setOptions(options);
6976		options = this.options;
6977		this.element = document.id(element);
6978		knob = this.knob = document.id(knob);
6979		this.previousChange = this.previousEnd = this.step = -1;
6980
6981		var limit = {},
6982			modifiers = {x: false, y: false};
6983
6984		switch (options.mode){
6985			case 'vertical':
6986				this.axis = 'y';
6987				this.property = 'top';
6988				this.offset = 'offsetHeight';
6989				break;
6990			case 'horizontal':
6991				this.axis = 'x';
6992				this.property = 'left';
6993				this.offset = 'offsetWidth';
6994		}
6995
6996		this.setSliderDimensions();
6997		this.setRange(options.range);
6998
6999		if (knob.getStyle('position') == 'static') knob.setStyle('position', 'relative');
7000		knob.setStyle(this.property, -options.offset);
7001		modifiers[this.axis] = this.property;
7002		limit[this.axis] = [-options.offset, this.full - options.offset];
7003
7004		var dragOptions = {
7005			snap: 0,
7006			limit: limit,
7007			modifiers: modifiers,
7008			onDrag: this.draggedKnob,
7009			onStart: this.draggedKnob,
7010			onBeforeStart: (function(){
7011				this.isDragging = true;
7012			}).bind(this),
7013			onCancel: function(){
7014				this.isDragging = false;
7015			}.bind(this),
7016			onComplete: function(){
7017				this.isDragging = false;
7018				this.draggedKnob();
7019				this.end();
7020			}.bind(this)
7021		};
7022		if (options.snap) this.setSnap(dragOptions);
7023
7024		this.drag = new Drag(knob, dragOptions);
7025		this.attach();
7026		if (options.initialStep != null) this.set(options.initialStep);
7027	},
7028
7029	attach: function(){
7030		this.element.addEvent('mousedown', this.clickedElement);
7031		if (this.options.wheel) this.element.addEvent('mousewheel', this.scrolledElement);
7032		this.drag.attach();
7033		return this;
7034	},
7035
7036	detach: function(){
7037		this.element.removeEvent('mousedown', this.clickedElement)
7038			.removeEvent('mousewheel', this.scrolledElement);
7039		this.drag.detach();
7040		return this;
7041	},
7042
7043	autosize: function(){
7044		this.setSliderDimensions()
7045			.setKnobPosition(this.toPosition(this.step));
7046		this.drag.options.limit[this.axis] = [-this.options.offset, this.full - this.options.offset];
7047		if (this.options.snap) this.setSnap();
7048		return this;
7049	},
7050
7051	setSnap: function(options){
7052		if (!options) options = this.drag.options;
7053		options.grid = Math.ceil(this.stepWidth);
7054		options.limit[this.axis][1] = this.full;
7055		return this;
7056	},
7057
7058	setKnobPosition: function(position){
7059		if (this.options.snap) position = this.toPosition(this.step);
7060		this.knob.setStyle(this.property, position);
7061		return this;
7062	},
7063
7064	setSliderDimensions: function(){
7065		this.full = this.element.measure(function(){
7066			this.half = this.knob[this.offset] / 2;
7067			return this.element[this.offset] - this.knob[this.offset] + (this.options.offset * 2);
7068		}.bind(this));
7069		return this;
7070	},
7071
7072	set: function(step){
7073		if (!((this.range > 0) ^ (step < this.min))) step = this.min;
7074		if (!((this.range > 0) ^ (step > this.max))) step = this.max;
7075
7076		this.step = Math.round(step);
7077		return this.checkStep()
7078			.fireEvent('tick', this.toPosition(this.step))
7079			.end();
7080	},
7081
7082	setRange: function(range, pos){
7083		this.min = Array.pick([range[0], 0]);
7084		this.max = Array.pick([range[1], this.options.steps]);
7085		this.range = this.max - this.min;
7086		this.steps = this.options.steps || this.full;
7087		this.stepSize = Math.abs(this.range) / this.steps;
7088		this.stepWidth = this.stepSize * this.full / Math.abs(this.range);
7089		if (range) this.set(Array.pick([pos, this.step]).floor(this.min).max(this.max));
7090		return this;
7091	},
7092
7093	clickedElement: function(event){
7094		if (this.isDragging || event.target == this.knob) return;
7095
7096		var dir = this.range < 0 ? -1 : 1,
7097			position = event.page[this.axis] - this.element.getPosition()[this.axis] - this.half;
7098
7099		position = position.limit(-this.options.offset, this.full - this.options.offset);
7100
7101		this.step = Math.round(this.min + dir * this.toStep(position));
7102
7103		this.checkStep()
7104			.fireEvent('tick', position)
7105			.end();
7106	},
7107
7108	scrolledElement: function(event){
7109		var mode = (this.options.mode == 'horizontal') ? (event.wheel < 0) : (event.wheel > 0);
7110		this.set(this.step + (mode ? -1 : 1) * this.stepSize);
7111		event.stop();
7112	},
7113
7114	draggedKnob: function(){
7115		var dir = this.range < 0 ? -1 : 1,
7116			position = this.drag.value.now[this.axis];
7117
7118		position = position.limit(-this.options.offset, this.full -this.options.offset);
7119
7120		this.step = Math.round(this.min + dir * this.toStep(position));
7121		this.checkStep();
7122	},
7123
7124	checkStep: function(){
7125		var step = this.step;
7126		if (this.previousChange != step){
7127			this.previousChange = step;
7128			this.fireEvent('change', step);
7129		}
7130		return this;
7131	},
7132
7133	end: function(){
7134		var step = this.step;
7135		if (this.previousEnd !== step){
7136			this.previousEnd = step;
7137			this.fireEvent('complete', step + '');
7138		}
7139		return this;
7140	},
7141
7142	toStep: function(position){
7143		var step = (position + this.options.offset) * this.stepSize / this.full * this.steps;
7144		return this.options.steps ? Math.round(step -= step % this.stepSize) : step;
7145	},
7146
7147	toPosition: function(step){
7148		return (this.full * Math.abs(this.min - step)) / (this.steps * this.stepSize) - this.options.offset;
7149	}
7150
7151});
7152
7153
7154/*
7155---
7156
7157script: Sortables.js
7158
7159name: Sortables
7160
7161description: Class for creating a drag and drop sorting interface for lists of items.
7162
7163license: MIT-style license
7164
7165authors:
7166  - Tom Occhino
7167
7168requires:
7169  - Core/Fx.Morph
7170  - /Drag.Move
7171
7172provides: [Sortables]
7173
7174...
7175*/
7176
7177var Sortables = new Class({
7178
7179	Implements: [Events, Options],
7180
7181	options: {/*
7182		onSort: function(element, clone){},
7183		onStart: function(element, clone){},
7184		onComplete: function(element){},*/
7185		opacity: 1,
7186		clone: false,
7187		revert: false,
7188		handle: false,
7189		dragOptions: {}
7190	},
7191
7192	initialize: function(lists, options){
7193		this.setOptions(options);
7194
7195		this.elements = [];
7196		this.lists = [];
7197		this.idle = true;
7198
7199		this.addLists($$(document.id(lists) || lists));
7200
7201		if (!this.options.clone) this.options.revert = false;
7202		if (this.options.revert) this.effect = new Fx.Morph(null, Object.merge({
7203			duration: 250,
7204			link: 'cancel'
7205		}, this.options.revert));
7206	},
7207
7208	attach: function(){
7209		this.addLists(this.lists);
7210		return this;
7211	},
7212
7213	detach: function(){
7214		this.lists = this.removeLists(this.lists);
7215		return this;
7216	},
7217
7218	addItems: function(){
7219		Array.flatten(arguments).each(function(element){
7220			this.elements.push(element);
7221			var start = element.retrieve('sortables:start', function(event){
7222				this.start.call(this, event, element);
7223			}.bind(this));
7224			(this.options.handle ? element.getElement(this.options.handle) || element : element).addEvent('mousedown', start);
7225		}, this);
7226		return this;
7227	},
7228
7229	addLists: function(){
7230		Array.flatten(arguments).each(function(list){
7231			this.lists.include(list);
7232			this.addItems(list.getChildren());
7233		}, this);
7234		return this;
7235	},
7236
7237	removeItems: function(){
7238		return $$(Array.flatten(arguments).map(function(element){
7239			this.elements.erase(element);
7240			var start = element.retrieve('sortables:start');
7241			(this.options.handle ? element.getElement(this.options.handle) || element : element).removeEvent('mousedown', start);
7242
7243			return element;
7244		}, this));
7245	},
7246
7247	removeLists: function(){
7248		return $$(Array.flatten(arguments).map(function(list){
7249			this.lists.erase(list);
7250			this.removeItems(list.getChildren());
7251
7252			return list;
7253		}, this));
7254	},
7255
7256	getClone: function(event, element){
7257		if (!this.options.clone) return new Element(element.tagName).inject(document.body);
7258		if (typeOf(this.options.clone) == 'function') return this.options.clone.call(this, event, element, this.list);
7259		var clone = element.clone(true).setStyles({
7260			margin: 0,
7261			position: 'absolute',
7262			visibility: 'hidden',
7263			width: element.getStyle('width')
7264		}).addEvent('mousedown', function(event){
7265			element.fireEvent('mousedown', event);
7266		});
7267		//prevent the duplicated radio inputs from unchecking the real one
7268		if (clone.get('html').test('radio')){
7269			clone.getElements('input[type=radio]').each(function(input, i){
7270				input.set('name', 'clone_' + i);
7271				if (input.get('checked')) element.getElements('input[type=radio]')[i].set('checked', true);
7272			});
7273		}
7274
7275		return clone.inject(this.list).setPosition(element.getPosition(element.getOffsetParent()));
7276	},
7277
7278	getDroppables: function(){
7279		var droppables = this.list.getChildren().erase(this.clone).erase(this.element);
7280		if (!this.options.constrain) droppables.append(this.lists).erase(this.list);
7281		return droppables;
7282	},
7283
7284	insert: function(dragging, element){
7285		var where = 'inside';
7286		if (this.lists.contains(element)){
7287			this.list = element;
7288			this.drag.droppables = this.getDroppables();
7289		} else {
7290			where = this.element.getAllPrevious().contains(element) ? 'before' : 'after';
7291		}
7292		this.element.inject(element, where);
7293		this.fireEvent('sort', [this.element, this.clone]);
7294	},
7295
7296	start: function(event, element){
7297		if (
7298			!this.idle ||
7299			event.rightClick ||
7300			['button', 'input', 'a', 'textarea'].contains(event.target.get('tag'))
7301		) return;
7302
7303		this.idle = false;
7304		this.element = element;
7305		this.opacity = element.getStyle('opacity');
7306		this.list = element.getParent();
7307		this.clone = this.getClone(event, element);
7308
7309		this.drag = new Drag.Move(this.clone, Object.merge({
7310			
7311			droppables: this.getDroppables()
7312		}, this.options.dragOptions)).addEvents({
7313			onSnap: function(){
7314				event.stop();
7315				this.clone.setStyle('visibility', 'visible');
7316				this.element.setStyle('opacity', this.options.opacity || 0);
7317				this.fireEvent('start', [this.element, this.clone]);
7318			}.bind(this),
7319			onEnter: this.insert.bind(this),
7320			onCancel: this.end.bind(this),
7321			onComplete: this.end.bind(this)
7322		});
7323
7324		this.clone.inject(this.element, 'before');
7325		this.drag.start(event);
7326	},
7327
7328	end: function(){
7329		this.drag.detach();
7330		this.element.setStyle('opacity', this.opacity);
7331		if (this.effect){
7332			var dim = this.element.getStyles('width', 'height'),
7333				clone = this.clone,
7334				pos = clone.computePosition(this.element.getPosition(this.clone.getOffsetParent()));
7335
7336			var destroy = function(){
7337				this.removeEvent('cancel', destroy);
7338				clone.destroy();
7339			};
7340
7341			this.effect.element = clone;
7342			this.effect.start({
7343				top: pos.top,
7344				left: pos.left,
7345				width: dim.width,
7346				height: dim.height,
7347				opacity: 0.25
7348			}).addEvent('cancel', destroy).chain(destroy);
7349		} else {
7350			this.clone.destroy();
7351		}
7352		this.reset();
7353	},
7354
7355	reset: function(){
7356		this.idle = true;
7357		this.fireEvent('complete', this.element);
7358	},
7359
7360	serialize: function(){
7361		var params = Array.link(arguments, {
7362			modifier: Type.isFunction,
7363			index: function(obj){
7364				return obj != null;
7365			}
7366		});
7367		var serial = this.lists.map(function(list){
7368			return list.getChildren().map(params.modifier || function(element){
7369				return element.get('id');
7370			}, this);
7371		}, this);
7372
7373		var index = params.index;
7374		if (this.lists.length == 1) index = 0;
7375		return (index || index === 0) && index >= 0 && index < this.lists.length ? serial[index] : serial;
7376	}
7377
7378});
7379
7380
7381/*
7382---
7383
7384script: Request.JSONP.js
7385
7386name: Request.JSONP
7387
7388description: Defines Request.JSONP, a class for cross domain javascript via script injection.
7389
7390license: MIT-style license
7391
7392authors:
7393  - Aaron Newton
7394  - Guillermo Rauch
7395  - Arian Stolwijk
7396
7397requires:
7398  - Core/Element
7399  - Core/Request
7400  - MooTools.More
7401
7402provides: [Request.JSONP]
7403
7404...
7405*/
7406
7407Request.JSONP = new Class({
7408
7409	Implements: [Chain, Events, Options],
7410
7411	options: {/*
7412		onRequest: function(src, scriptElement){},
7413		onComplete: function(data){},
7414		onSuccess: function(data){},
7415		onCancel: function(){},
7416		onTimeout: function(){},
7417		onError: function(){}, */
7418		onRequest: function(src){
7419			if (this.options.log && window.console && console.log){
7420				console.log('JSONP retrieving script with url:' + src);
7421			}
7422		},
7423		onError: function(src){
7424			if (this.options.log && window.console && console.warn){
7425				console.warn('JSONP '+ src +' will fail in Internet Explorer, which enforces a 2083 bytes length limit on URIs');
7426			}
7427		},
7428		url: '',
7429		callbackKey: 'callback',
7430		injectScript: document.head,
7431		data: '',
7432		link: 'ignore',
7433		timeout: 0,
7434		log: false
7435	},
7436
7437	initialize: function(options){
7438		this.setOptions(options);
7439	},
7440
7441	send: function(options){
7442		if (!Request.prototype.check.call(this, options)) return this;
7443		this.running = true;
7444
7445		var type = typeOf(options);
7446		if (type == 'string' || type == 'element') options = {data: options};
7447		options = Object.merge(this.options, options || {});
7448
7449		var data = options.data;
7450		switch (typeOf(data)){
7451			case 'element': data = document.id(data).toQueryString(); break;
7452			case 'object': case 'hash': data = Object.toQueryString(data);
7453		}
7454
7455		var index = this.index = Request.JSONP.counter++;
7456
7457		var src = options.url +
7458			(options.url.test('\\?') ? '&' :'?') +
7459			(options.callbackKey) +
7460			'=Request.JSONP.request_map.request_'+ index +
7461			(data ? '&' + data : '');
7462
7463		if (src.length > 2083) this.fireEvent('error', src);
7464
7465		Request.JSONP.request_map['request_' + index] = function(){
7466			this.success(arguments, index);
7467		}.bind(this);
7468
7469		var script = this.getScript(src).inject(options.injectScript);
7470		this.fireEvent('request', [src, script]);
7471
7472		if (options.timeout) this.timeout.delay(options.timeout, this);
7473
7474		return this;
7475	},
7476
7477	getScript: function(src){
7478		if (!this.script) this.script = new Element('script', {
7479			type: 'text/javascript',
7480			async: true,
7481			src: src
7482		});
7483		return this.script;
7484	},
7485
7486	success: function(args, index){
7487		if (!this.running) return;
7488		this.clear()
7489			.fireEvent('complete', args).fireEvent('success', args)
7490			.callChain();
7491	},
7492
7493	cancel: function(){
7494		if (this.running) this.clear().fireEvent('cancel');
7495		return this;
7496	},
7497
7498	isRunning: function(){
7499		return !!this.running;
7500	},
7501
7502	clear: function(){
7503		this.running = false;
7504		if (this.script){
7505			this.script.destroy();
7506			this.script = null;
7507		}
7508		return this;
7509	},
7510
7511	timeout: function(){
7512		if (this.running){
7513			this.running = false;
7514			this.fireEvent('timeout', [this.script.get('src'), this.script]).fireEvent('failure').cancel();
7515		}
7516		return this;
7517	}
7518
7519});
7520
7521Request.JSONP.counter = 0;
7522Request.JSONP.request_map = {};
7523
7524
7525/*
7526---
7527
7528script: Request.Queue.js
7529
7530name: Request.Queue
7531
7532description: Controls several instances of Request and its variants to run only one request at a time.
7533
7534license: MIT-style license
7535
7536authors:
7537  - Aaron Newton
7538
7539requires:
7540  - Core/Element
7541  - Core/Request
7542  - /Class.Binds
7543
7544provides: [Request.Queue]
7545
7546...
7547*/
7548
7549Request.Queue = new Class({
7550
7551	Implements: [Options, Events],
7552
7553	Binds: ['attach', 'request', 'complete', 'cancel', 'success', 'failure', 'exception'],
7554
7555	options: {/*
7556		onRequest: function(argsPassedToOnRequest){},
7557		onSuccess: function(argsPassedToOnSuccess){},
7558		onComplete: function(argsPassedToOnComplete){},
7559		onCancel: function(argsPassedToOnCancel){},
7560		onException: function(argsPassedToOnException){},
7561		onFailure: function(argsPassedToOnFailure){},
7562		onEnd: function(){},
7563		*/
7564		stopOnFailure: true,
7565		autoAdvance: true,
7566		concurrent: 1,
7567		requests: {}
7568	},
7569
7570	initialize: function(options){
7571		var requests;
7572		if (options){
7573			requests = options.requests;
7574			delete options.requests;
7575		}
7576		this.setOptions(options);
7577		this.requests = {};
7578		this.queue = [];
7579		this.reqBinders = {};
7580
7581		if (requests) this.addRequests(requests);
7582	},
7583
7584	addRequest: function(name, request){
7585		this.requests[name] = request;
7586		this.attach(name, request);
7587		return this;
7588	},
7589
7590	addRequests: function(obj){
7591		Object.each(obj, function(req, name){
7592			this.addRequest(name, req);
7593		}, this);
7594		return this;
7595	},
7596
7597	getName: function(req){
7598		return Object.keyOf(this.requests, req);
7599	},
7600
7601	attach: function(name, req){
7602		if (req._groupSend) return this;
7603		['request', 'complete', 'cancel', 'success', 'failure', 'exception'].each(function(evt){
7604			if (!this.reqBinders[name]) this.reqBinders[name] = {};
7605			this.reqBinders[name][evt] = function(){
7606				this['on' + evt.capitalize()].apply(this, [name, req].append(arguments));
7607			}.bind(this);
7608			req.addEvent(evt, this.reqBinders[name][evt]);
7609		}, this);
7610		req._groupSend = req.send;
7611		req.send = function(options){
7612			this.send(name, options);
7613			return req;
7614		}.bind(this);
7615		return this;
7616	},
7617
7618	removeRequest: function(req){
7619		var name = typeOf(req) == 'object' ? this.getName(req) : req;
7620		if (!name && typeOf(name) != 'string') return this;
7621		req = this.requests[name];
7622		if (!req) return this;
7623		['request', 'complete', 'cancel', 'success', 'failure', 'exception'].each(function(evt){
7624			req.removeEvent(evt, this.reqBinders[name][evt]);
7625		}, this);
7626		req.send = req._groupSend;
7627		delete req._groupSend;
7628		return this;
7629	},
7630
7631	getRunning: function(){
7632		return Object.filter(this.requests, function(r){
7633			return r.running;
7634		});
7635	},
7636
7637	isRunning: function(){
7638		return !!(Object.keys(this.getRunning()).length);
7639	},
7640
7641	send: function(name, options){
7642		var q = function(){
7643			this.requests[name]._groupSend(options);
7644			this.queue.erase(q);
7645		}.bind(this);
7646
7647		q.name = name;
7648		if (Object.keys(this.getRunning()).length >= this.options.concurrent || (this.error && this.options.stopOnFailure)) this.queue.push(q);
7649		else q();
7650		return this;
7651	},
7652
7653	hasNext: function(name){
7654		return (!name) ? !!this.queue.length : !!this.queue.filter(function(q){ return q.name == name; }).length;
7655	},
7656
7657	resume: function(){
7658		this.error = false;
7659		(this.options.concurrent - Object.keys(this.getRunning()).length).times(this.runNext, this);
7660		return this;
7661	},
7662
7663	runNext: function(name){
7664		if (!this.queue.length) return this;
7665		if (!name){
7666			this.queue[0]();
7667		} else {
7668			var found;
7669			this.queue.each(function(q){
7670				if (!found && q.name == name){
7671					found = true;
7672					q();
7673				}
7674			});
7675		}
7676		return this;
7677	},
7678
7679	runAll: function(){
7680		this.queue.each(function(q){
7681			q();
7682		});
7683		return this;
7684	},
7685
7686	clear: function(name){
7687		if (!name){
7688			this.queue.empty();
7689		} else {
7690			this.queue = this.queue.map(function(q){
7691				if (q.name != name) return q;
7692				else return false;
7693			}).filter(function(q){
7694				return q;
7695			});
7696		}
7697		return this;
7698	},
7699
7700	cancel: function(name){
7701		this.requests[name].cancel();
7702		return this;
7703	},
7704
7705	onRequest: function(){
7706		this.fireEvent('request', arguments);
7707	},
7708
7709	onComplete: function(){
7710		this.fireEvent('complete', arguments);
7711		if (!this.queue.length) this.fireEvent('end');
7712	},
7713
7714	onCancel: function(){
7715		if (this.options.autoAdvance && !this.error) this.runNext();
7716		this.fireEvent('cancel', arguments);
7717	},
7718
7719	onSuccess: function(){
7720		if (this.options.autoAdvance && !this.error) this.runNext();
7721		this.fireEvent('success', arguments);
7722	},
7723
7724	onFailure: function(){
7725		this.error = true;
7726		if (!this.options.stopOnFailure && this.options.autoAdvance) this.runNext();
7727		this.fireEvent('failure', arguments);
7728	},
7729
7730	onException: function(){
7731		this.error = true;
7732		if (!this.options.stopOnFailure && this.options.autoAdvance) this.runNext();
7733		this.fireEvent('exception', arguments);
7734	}
7735
7736});
7737
7738
7739/*
7740---
7741
7742script: Request.Periodical.js
7743
7744name: Request.Periodical
7745
7746description: Requests the same URL to pull data from a server but increases the intervals if no data is returned to reduce the load
7747
7748license: MIT-style license
7749
7750authors:
7751  - Christoph Pojer
7752
7753requires:
7754  - Core/Request
7755  - /MooTools.More
7756
7757provides: [Request.Periodical]
7758
7759...
7760*/
7761
7762Request.implement({
7763
7764	options: {
7765		initialDelay: 5000,
7766		delay: 5000,
7767		limit: 60000
7768	},
7769
7770	startTimer: function(data){
7771		var fn = function(){
7772			if (!this.running) this.send({data: data});
7773		};
7774		this.lastDelay = this.options.initialDelay;
7775		this.timer = fn.delay(this.lastDelay, this);
7776		this.completeCheck = function(response){
7777			clearTimeout(this.timer);
7778			this.lastDelay = (response) ? this.options.delay : (this.lastDelay + this.options.delay).min(this.options.limit);
7779			this.timer = fn.delay(this.lastDelay, this);
7780		};
7781		return this.addEvent('complete', this.completeCheck);
7782	},
7783
7784	stopTimer: function(){
7785		clearTimeout(this.timer);
7786		return this.removeEvent('complete', this.completeCheck);
7787	}
7788
7789});
7790
7791
7792/*
7793---
7794
7795script: Assets.js
7796
7797name: Assets
7798
7799description: Provides methods to dynamically load JavaScript, CSS, and Image files into the document.
7800
7801license: MIT-style license
7802
7803authors:
7804  - Valerio Proietti
7805
7806requires:
7807  - Core/Element.Event
7808  - /MooTools.More
7809
7810provides: [Assets]
7811
7812...
7813*/
7814
7815var Asset = {
7816
7817	javascript: function(source, properties){
7818		if (!properties) properties = {};
7819
7820		var script = new Element('script', {src: source, type: 'text/javascript'}),
7821			doc = properties.document || document,
7822			load = properties.onload || properties.onLoad;
7823
7824		delete properties.onload;
7825		delete properties.onLoad;
7826		delete properties.document;
7827
7828		if (load){
7829			if (typeof script.onreadystatechange != 'undefined'){
7830				script.addEvent('readystatechange', function(){
7831					if (['loaded', 'complete'].contains(this.readyState)) load.call(this);
7832				});
7833			} else {
7834				script.addEvent('load', load);
7835			}
7836		}
7837
7838		return script.set(properties).inject(doc.head);
7839	},
7840
7841	css: function(source, properties){
7842		if (!properties) properties = {};
7843
7844		var link = new Element('link', {
7845			rel: 'stylesheet',
7846			media: 'screen',
7847			type: 'text/css',
7848			href: source
7849		});
7850
7851		var load = properties.onload || properties.onLoad,
7852			doc = properties.document || document;
7853
7854		delete properties.onload;
7855		delete properties.onLoad;
7856		delete properties.document;
7857
7858		if (load) link.addEvent('load', load);
7859		return link.set(properties).inject(doc.head);
7860	},
7861
7862	image: function(source, properties){
7863		if (!properties) properties = {};
7864
7865		var image = new Image(),
7866			element = document.id(image) || new Element('img');
7867
7868		['load', 'abort', 'error'].each(function(name){
7869			var type = 'on' + name,
7870				cap = 'on' + name.capitalize(),
7871				event = properties[type] || properties[cap] || function(){};
7872
7873			delete properties[cap];
7874			delete properties[type];
7875
7876			image[type] = function(){
7877				if (!image) return;
7878				if (!element.parentNode){
7879					element.width = image.width;
7880					element.height = image.height;
7881				}
7882				image = image.onload = image.onabort = image.onerror = null;
7883				event.delay(1, element, element);
7884				element.fireEvent(name, element, 1);
7885			};
7886		});
7887
7888		image.src = element.src = source;
7889		if (image && image.complete) image.onload.delay(1);
7890		return element.set(properties);
7891	},
7892
7893	images: function(sources, options){
7894		sources = Array.from(sources);
7895
7896		var fn = function(){},
7897			counter = 0;
7898
7899		options = Object.merge({
7900			onComplete: fn,
7901			onProgress: fn,
7902			onError: fn,
7903			properties: {}
7904		}, options);
7905
7906		return new Elements(sources.map(function(source, index){
7907			return Asset.image(source, Object.append(options.properties, {
7908				onload: function(){
7909					counter++;
7910					options.onProgress.call(this, counter, index, source);
7911					if (counter == sources.length) options.onComplete();
7912				},
7913				onerror: function(){
7914					counter++;
7915					options.onError.call(this, counter, index, source);
7916					if (counter == sources.length) options.onComplete();
7917				}
7918			}));
7919		}));
7920	}
7921
7922};
7923
7924
7925/*
7926---
7927
7928script: Color.js
7929
7930name: Color
7931
7932description: Class for creating and manipulating colors in JavaScript. Supports HSB -> RGB Conversions and vice versa.
7933
7934license: MIT-style license
7935
7936authors:
7937  - Valerio Proietti
7938
7939requires:
7940  - Core/Array
7941  - Core/String
7942  - Core/Number
7943  - Core/Hash
7944  - Core/Function
7945  - MooTools.More
7946
7947provides: [Color]
7948
7949...
7950*/
7951
7952(function(){
7953
7954var Color = this.Color = new Type('Color', function(color, type){
7955	if (arguments.length >= 3){
7956		type = 'rgb'; color = Array.slice(arguments, 0, 3);
7957	} else if (typeof color == 'string'){
7958		if (color.match(/rgb/)) color = color.rgbToHex().hexToRgb(true);
7959		else if (color.match(/hsb/)) color = color.hsbToRgb();
7960		else color = color.hexToRgb(true);
7961	}
7962	type = type || 'rgb';
7963	switch (type){
7964		case 'hsb':
7965			var old = color;
7966			color = color.hsbToRgb();
7967			color.hsb = old;
7968		break;
7969		case 'hex': color = color.hexToRgb(true); break;
7970	}
7971	color.rgb = color.slice(0, 3);
7972	color.hsb = color.hsb || color.rgbToHsb();
7973	color.hex = color.rgbToHex();
7974	return Object.append(color, this);
7975});
7976
7977Color.implement({
7978
7979	mix: function(){
7980		var colors = Array.slice(arguments);
7981		var alpha = (typeOf(colors.getLast()) == 'number') ? colors.pop() : 50;
7982		var rgb = this.slice();
7983		colors.each(function(color){
7984			color = new Color(color);
7985			for (var i = 0; i < 3; i++) rgb[i] = Math.round((rgb[i] / 100 * (100 - alpha)) + (color[i] / 100 * alpha));
7986		});
7987		return new Color(rgb, 'rgb');
7988	},
7989
7990	invert: function(){
7991		return new Color(this.map(function(value){
7992			return 255 - value;
7993		}));
7994	},
7995
7996	setHue: function(value){
7997		return new Color([value, this.hsb[1], this.hsb[2]], 'hsb');
7998	},
7999
8000	setSaturation: function(percent){
8001		return new Color([this.hsb[0], percent, this.hsb[2]], 'hsb');
8002	},
8003
8004	setBrightness: function(percent){
8005		return new Color([this.hsb[0], this.hsb[1], percent], 'hsb');
8006	}
8007
8008});
8009
8010this.$RGB = function(r, g, b){
8011	return new Color([r, g, b], 'rgb');
8012};
8013
8014this.$HSB = function(h, s, b){
8015	return new Color([h, s, b], 'hsb');
8016};
8017
8018this.$HEX = function(hex){
8019	return new Color(hex, 'hex');
8020};
8021
8022Array.implement({
8023
8024	rgbToHsb: function(){
8025		var red = this[0],
8026				green = this[1],
8027				blue = this[2],
8028				hue = 0;
8029		var max = Math.max(red, green, blue),
8030				min = Math.min(red, green, blue);
8031		var delta = max - min;
8032		var brightness = max / 255,
8033				saturation = (max != 0) ? delta / max : 0;
8034		if (saturation != 0){
8035			var rr = (max - red) / delta;
8036			var gr = (max - green) / delta;
8037			var br = (max - blue) / delta;
8038			if (red == max) hue = br - gr;
8039			else if (green == max) hue = 2 + rr - br;
8040			else hue = 4 + gr - rr;
8041			hue /= 6;
8042			if (hue < 0) hue++;
8043		}
8044		return [Math.round(hue * 360), Math.round(saturation * 100), Math.round(brightness * 100)];
8045	},
8046
8047	hsbToRgb: function(){
8048		var br = Math.round(this[2] / 100 * 255);
8049		if (this[1] == 0){
8050			return [br, br, br];
8051		} else {
8052			var hue = this[0] % 360;
8053			var f = hue % 60;
8054			var p = Math.round((this[2] * (100 - this[1])) / 10000 * 255);
8055			var q = Math.round((this[2] * (6000 - this[1] * f)) / 600000 * 255);
8056			var t = Math.round((this[2] * (6000 - this[1] * (60 - f))) / 600000 * 255);
8057			switch (Math.floor(hue / 60)){
8058				case 0: return [br, t, p];
8059				case 1: return [q, br, p];
8060				case 2: return [p, br, t];
8061				case 3: return [p, q, br];
8062				case 4: return [t, p, br];
8063				case 5: return [br, p, q];
8064			}
8065		}
8066		return false;
8067	}
8068
8069});
8070
8071String.implement({
8072
8073	rgbToHsb: function(){
8074		var rgb = this.match(/\d{1,3}/g);
8075		return (rgb) ? rgb.rgbToHsb() : null;
8076	},
8077
8078	hsbToRgb: function(){
8079		var hsb = this.match(/\d{1,3}/g);
8080		return (hsb) ? hsb.hsbToRgb() : null;
8081	}
8082
8083});
8084
8085})();
8086
8087
8088
8089/*
8090---
8091
8092script: Group.js
8093
8094name: Group
8095
8096description: Class for monitoring collections of events
8097
8098license: MIT-style license
8099
8100authors:
8101  - Valerio Proietti
8102
8103requires:
8104  - Core/Events
8105  - /MooTools.More
8106
8107provides: [Group]
8108
8109...
8110*/
8111
8112(function(){
8113
8114this.Group = new Class({
8115
8116	initialize: function(){
8117		this.instances = Array.flatten(arguments);
8118	},
8119
8120	addEvent: function(type, fn){
8121		var instances = this.instances,
8122			len = instances.length,
8123			togo = len,
8124			args = new Array(len),
8125			self = this;
8126
8127		instances.each(function(instance, i){
8128			instance.addEvent(type, function(){
8129				if (!args[i]) togo--;
8130				args[i] = arguments;
8131				if (!togo){
8132					fn.call(self, instances, instance, args);
8133					togo = len;
8134					args = new Array(len);
8135				}
8136			});
8137		});
8138	}
8139
8140});
8141
8142})();
8143
8144
8145/*
8146---
8147
8148script: Hash.Cookie.js
8149
8150name: Hash.Cookie
8151
8152description: Class for creating, reading, and deleting Cookies in JSON format.
8153
8154license: MIT-style license
8155
8156authors:
8157  - Valerio Proietti
8158  - Aaron Newton
8159
8160requires:
8161  - Core/Cookie
8162  - Core/JSON
8163  - /MooTools.More
8164  - /Hash
8165
8166provides: [Hash.Cookie]
8167
8168...
8169*/
8170
8171Hash.Cookie = new Class({
8172
8173	Extends: Cookie,
8174
8175	options: {
8176		autoSave: true
8177	},
8178
8179	initialize: function(name, options){
8180		this.parent(name, options);
8181		this.load();
8182	},
8183
8184	save: function(){
8185		var value = JSON.encode(this.hash);
8186		if (!value || value.length > 4096) return false; //cookie would be truncated!
8187		if (value == '{}') this.dispose();
8188		else this.write(value);
8189		return true;
8190	},
8191
8192	load: function(){
8193		this.hash = new Hash(JSON.decode(this.read(), true));
8194		return this;
8195	}
8196
8197});
8198
8199Hash.each(Hash.prototype, function(method, name){
8200	if (typeof method == 'function') Hash.Cookie.implement(name, function(){
8201		var value = method.apply(this.hash, arguments);
8202		if (this.options.autoSave) this.save();
8203		return value;
8204	});
8205});
8206
8207
8208/*
8209---
8210name: Table
8211description: LUA-Style table implementation.
8212license: MIT-style license
8213authors:
8214  - Valerio Proietti
8215requires: [Core/Array]
8216provides: [Table]
8217...
8218*/
8219
8220(function(){
8221
8222var Table = this.Table = function(){
8223
8224	this.length = 0;
8225	var keys = [],
8226	    values = [];
8227	
8228	this.set = function(key, value){
8229		var index = keys.indexOf(key);
8230		if (index == -1){
8231			var length = keys.length;
8232			keys[length] = key;
8233			values[length] = value;
8234			this.length++;
8235		} else {
8236			values[index] = value;
8237		}
8238		return this;
8239	};
8240
8241	this.get = function(key){
8242		var index = keys.indexOf(key);
8243		return (index == -1) ? null : values[index];
8244	};
8245
8246	this.erase = function(key){
8247		var index = keys.indexOf(key);
8248		if (index != -1){
8249			this.length--;
8250			keys.splice(index, 1);
8251			return values.splice(index, 1)[0];
8252		}
8253		return null;
8254	};
8255
8256	this.each = this.forEach = function(fn, bind){
8257		for (var i = 0, l = this.length; i < l; i++) fn.call(bind, keys[i], values[i], this);
8258	};
8259	
8260};
8261
8262if (this.Type) new Type('Table', Table);
8263
8264})();
8265
8266
8267/*
8268---
8269
8270script: HtmlTable.js
8271
8272name: HtmlTable
8273
8274description: Builds table elements with methods to add rows.
8275
8276license: MIT-style license
8277
8278authors:
8279  - Aaron Newton
8280
8281requires:
8282  - Core/Options
8283  - Core/Events
8284  - /Class.Occlude
8285
8286provides: [HtmlTable]
8287
8288...
8289*/
8290
8291var HtmlTable = new Class({
8292
8293	Implements: [Options, Events, Class.Occlude],
8294
8295	options: {
8296		properties: {
8297			cellpadding: 0,
8298			cellspacing: 0,
8299			border: 0
8300		},
8301		rows: [],
8302		headers: [],
8303		footers: []
8304	},
8305
8306	property: 'HtmlTable',
8307
8308	initialize: function(){
8309		var params = Array.link(arguments, {options: Type.isObject, table: Type.isElement, id: Type.isString});
8310		this.setOptions(params.options);
8311		if (!params.table && params.id) params.table = document.id(params.id);
8312		this.element = params.table || new Element('table', this.options.properties);
8313		if (this.occlude()) return this.occluded;
8314		this.build();
8315	},
8316
8317	build: function(){
8318		this.element.store('HtmlTable', this);
8319
8320		this.body = document.id(this.element.tBodies[0]) || new Element('tbody').inject(this.element);
8321		$$(this.body.rows);
8322
8323		if (this.options.headers.length) this.setHeaders(this.options.headers);
8324		else this.thead = document.id(this.element.tHead);
8325
8326		if (this.thead) this.head = this.getHead();
8327		if (this.options.footers.length) this.setFooters(this.options.footers);
8328
8329		this.tfoot = document.id(this.element.tFoot);
8330		if (this.tfoot) this.foot = document.id(this.tfoot.rows[0]);
8331
8332		this.options.rows.each(function(row){
8333			this.push(row);
8334		}, this);
8335	},
8336
8337	toElement: function(){
8338		return this.element;
8339	},
8340
8341	empty: function(){
8342		this.body.empty();
8343		return this;
8344	},
8345
8346	set: function(what, items){
8347		var target = (what == 'headers') ? 'tHead' : 'tFoot',
8348			lower = target.toLowerCase();
8349
8350		this[lower] = (document.id(this.element[target]) || new Element(lower).inject(this.element, 'top')).empty();
8351		var data = this.push(items, {}, this[lower], what == 'headers' ? 'th' : 'td');
8352
8353		if (what == 'headers') this.head = this.getHead();
8354		else this.foot = this.getHead();
8355
8356		return data;
8357	},
8358
8359	getHead: function(){
8360		var rows = this.thead.rows;
8361		return rows.length > 1 ? $$(rows) : rows.length ? document.id(rows[0]) : false;
8362	},
8363
8364	setHeaders: function(headers){
8365		this.set('headers', headers);
8366		return this;
8367	},
8368
8369	setFooters: function(footers){
8370		this.set('footers', footers);
8371		return this;
8372	},
8373
8374	update: function(tr, row, tag){
8375		var tds = tr.getChildren(tag || 'td'), last = tds.length - 1;
8376
8377		row.each(function(data, index){
8378			var td = tds[index] || new Element(tag || 'td').inject(tr),
8379				content = (data ? data.content : '') || data,
8380				type = typeOf(content);
8381
8382			if (data && data.properties) td.set(data.properties);
8383			if (/(element(s?)|array|collection)/.test(type)) td.empty().adopt(content);
8384			else td.set('html', content);
8385
8386			if (index > last) tds.push(td);
8387			else tds[index] = td;
8388		});
8389
8390		return {
8391			tr: tr,
8392			tds: tds
8393		};
8394	},
8395
8396	push: function(row, rowProperties, target, tag, where){
8397		if (typeOf(row) == 'element' && row.get('tag') == 'tr'){
8398			row.inject(target || this.body, where);
8399			return {
8400				tr: row,
8401				tds: row.getChildren('td')
8402			};
8403		}
8404		return this.update(new Element('tr', rowProperties).inject(target || this.body, where), row, tag);
8405	},
8406
8407	pushMany: function(rows, rowProperties, target, tag, where){
8408		return rows.map(function(row){
8409			return this.push(row, rowProperties, target, tag, where);
8410		}, this);
8411	}
8412
8413});
8414
8415
8416['adopt', 'inject', 'wraps', 'grab', 'replaces', 'dispose'].each(function(method){
8417	HtmlTable.implement(method, function(){
8418		this.element[method].apply(this.element, arguments);
8419		return this;
8420	});
8421});
8422
8423
8424
8425
8426/*
8427---
8428
8429script: HtmlTable.Zebra.js
8430
8431name: HtmlTable.Zebra
8432
8433description: Builds a stripy table with methods to add rows.
8434
8435license: MIT-style license
8436
8437authors:
8438  - Harald Kirschner
8439  - Aaron Newton
8440
8441requires:
8442  - /HtmlTable
8443  - /Element.Shortcuts
8444  - /Class.refactor
8445
8446provides: [HtmlTable.Zebra]
8447
8448...
8449*/
8450
8451HtmlTable = Class.refactor(HtmlTable, {
8452
8453	options: {
8454		classZebra: 'table-tr-odd',
8455		zebra: true,
8456		zebraOnlyVisibleRows: true
8457	},
8458
8459	initialize: function(){
8460		this.previous.apply(this, arguments);
8461		if (this.occluded) return this.occluded;
8462		if (this.options.zebra) this.updateZebras();
8463	},
8464
8465	updateZebras: function(){
8466		var index = 0;
8467		Array.each(this.body.rows, function(row){
8468			if (!this.options.zebraOnlyVisibleRows || row.isDisplayed()){
8469				this.zebra(row, index++);
8470			}
8471		}, this);
8472	},
8473
8474	setRowStyle: function(row, i){
8475		if (this.previous) this.previous(row, i);
8476		this.zebra(row, i);
8477	},
8478
8479	zebra: function(row, i){
8480		return row[((i % 2) ? 'remove' : 'add')+'Class'](this.options.classZebra);
8481	},
8482
8483	push: function(){
8484		var pushed = this.previous.apply(this, arguments);
8485		if (this.options.zebra) this.updateZebras();
8486		return pushed;
8487	}
8488
8489});
8490
8491
8492/*
8493---
8494
8495script: HtmlTable.Sort.js
8496
8497name: HtmlTable.Sort
8498
8499description: Builds a stripy, sortable table with methods to add rows.
8500
8501license: MIT-style license
8502
8503authors:
8504  - Harald Kirschner
8505  - Aaron Newton
8506  - Jacob Thornton
8507
8508requires:
8509  - Core/Hash
8510  - /HtmlTable
8511  - /Class.refactor
8512  - /Element.Delegation
8513  - /String.Extras
8514  - /Date
8515
8516provides: [HtmlTable.Sort]
8517
8518...
8519*/
8520
8521HtmlTable = Class.refactor(HtmlTable, {
8522
8523	options: {/*
8524		onSort: function(){}, */
8525		sortIndex: 0,
8526		sortReverse: false,
8527		parsers: [],
8528		defaultParser: 'string',
8529		classSortable: 'table-sortable',
8530		classHeadSort: 'table-th-sort',
8531		classHeadSortRev: 'table-th-sort-rev',
8532		classNoSort: 'table-th-nosort',
8533		classGroupHead: 'table-tr-group-head',
8534		classGroup: 'table-tr-group',
8535		classCellSort: 'table-td-sort',
8536		classSortSpan: 'table-th-sort-span',
8537		sortable: false,
8538		thSelector: 'th'
8539	},
8540
8541	initialize: function (){
8542		this.previous.apply(this, arguments);
8543		if (this.occluded) return this.occluded;
8544		this.sorted = {index: null, dir: 1};
8545		if (!this.bound) this.bound = {};
8546		this.bound.headClick = this.headClick.bind(this);
8547		this.sortSpans = new Elements();
8548		if (this.options.sortable){
8549			this.enableSort();
8550			if (this.options.sortIndex != null) this.sort(this.options.sortIndex, this.options.sortReverse);
8551		}
8552	},
8553
8554	attachSorts: function(attach){
8555		this.detachSorts();
8556		if (attach !== false) this.element.addEvent('click:relay(' + this.options.thSelector + ')', this.bound.headClick);
8557	},
8558
8559	detachSorts: function(){
8560		this.element.removeEvents('click:relay(' + this.options.thSelector + ')');
8561	},
8562
8563	setHeaders: function(){
8564		this.previous.apply(this, arguments);
8565		if (this.sortEnabled) this.setParsers();
8566	},
8567
8568	setParsers: function(){
8569		this.parsers = this.detectParsers();
8570	},
8571
8572	detectParsers: function(){
8573		return this.head && this.head.getElements(this.options.thSelector).flatten().map(this.detectParser, this);
8574	},
8575
8576	detectParser: function(cell, index){
8577		if (cell.hasClass(this.options.classNoSort) || cell.retrieve('htmltable-parser')) return cell.retrieve('htmltable-parser');
8578		var thDiv = new Element('div');
8579		thDiv.adopt(cell.childNodes).inject(cell);
8580		var sortSpan = new Element('span', {'class': this.options.classSortSpan}).inject(thDiv, 'top');
8581		this.sortSpans.push(sortSpan);
8582		var parser = this.options.parsers[index],
8583			rows = this.body.rows,
8584			cancel;
8585		switch (typeOf(parser)){
8586			case 'function': parser = {convert: parser}; cancel = true; break;
8587			case 'string': parser = parser; cancel = true; break;
8588		}
8589		if (!cancel){
8590			HtmlTable.ParserPriority.some(function(parserName){
8591				var current = HtmlTable.Parsers[parserName],
8592					match = current.match;
8593				if (!match) return false;
8594				for (var i = 0, j = rows.length; i < j; i++){
8595					var cell = document.id(rows[i].cells[index]),
8596						text = cell ? cell.get('html').clean() : '';
8597					if (text && match.test(text)){
8598						parser = current;
8599						return true;
8600					}
8601				}
8602			});
8603		}
8604		if (!parser) parser = this.options.defaultParser;
8605		cell.store('htmltable-parser', parser);
8606		return parser;
8607	},
8608
8609	headClick: function(event, el){
8610		if (!this.head || el.hasClass(this.options.classNoSort)) return;
8611		return this.sort(Array.indexOf(this.head.getElements(this.options.thSelector).flatten(), el) % this.body.rows[0].cells.length);
8612	},
8613
8614	serialize: function(){
8615		var previousSerialization = this.previous.apply(this, arguments) || {};
8616		if (this.options.sortable){
8617			previousSerialization.sortIndex = this.sorted.index;
8618			previousSerialization.sortReverse = this.sorted.reverse;
8619		}
8620		return previousSerialization;
8621	},
8622
8623	restore: function(tableState){
8624		if (this.options.sortable && tableState.sortIndex){
8625			this.sort(tableState.sortIndex, tableState.sortReverse);
8626		}
8627		this.previous.apply(this, arguments);
8628	},
8629
8630	setSortedState: function(index, reverse){
8631		if (reverse != null) this.sorted.reverse = reverse;
8632		else if (this.sorted.index == index) this.sorted.reverse = !this.sorted.reverse;
8633		else this.sorted.reverse = this.sorted.index == null;
8634
8635		if (index != null) this.sorted.index = index;
8636	},
8637
8638	setHeadSort: function(sorted){
8639		var head = $$(!this.head.length ? this.head.cells[this.sorted.index] : this.head.map(function(row){
8640			return row.getElements(this.options.thSelector)[this.sorted.index];
8641		}, this).clean());
8642		if (!head.length) return;
8643		if (sorted){
8644			head.addClass(this.options.classHeadSort);
8645			if (this.sorted.reverse) head.addClass(this.options.classHeadSortRev);
8646			else head.removeClass(this.options.classHeadSortRev);
8647		} else {
8648			head.removeClass(this.options.classHeadSort).removeClass(this.options.classHeadSortRev);
8649		}
8650	},
8651
8652	setRowSort: function(data, pre){
8653		var count = data.length,
8654			body = this.body,
8655			group,
8656			rowIndex;
8657
8658		while (count){
8659			var item = data[--count],
8660				position = item.position,
8661				row = body.rows[position];
8662
8663			if (row.disabled) continue;
8664			if (!pre){
8665				group = this.setGroupSort(group, row, item);
8666				this.setRowStyle(row, count);
8667			}
8668			body.appendChild(row);
8669
8670			for (rowIndex = 0; rowIndex < count; rowIndex++){
8671				if (data[rowIndex].position > position) data[rowIndex].position--;
8672			}
8673		}
8674	},
8675
8676	setRowStyle: function(row, i){
8677		this.previous(row, i);
8678		row.cells[this.sorted.index].addClass(this.options.classCellSort);
8679	},
8680
8681	setGroupSort: function(group, row, item){
8682		if (group == item.value) row.removeClass(this.options.classGroupHead).addClass(this.options.classGroup);
8683		else row.removeClass(this.options.classGroup).addClass(this.options.classGroupHead);
8684		return item.value;
8685	},
8686
8687	getParser: function(){
8688		var parser = this.parsers[this.sorted.index];
8689		return typeOf(parser) == 'string' ? HtmlTable.Parsers[parser] : parser;
8690	},
8691
8692	sort: function(index, reverse, pre){
8693		if (!this.head) return;
8694
8695		if (!pre){
8696			this.clearSort();
8697			this.setSortedState(index, reverse);
8698			this.setHeadSort(true);
8699		}
8700
8701		var parser = this.getParser();
8702		if (!parser) return;
8703
8704		var rel;
8705		if (!Browser.ie){
8706			rel = this.body.getParent();
8707			this.body.dispose();
8708		}
8709
8710		var data = this.parseData(parser).sort(function(a, b){
8711			if (a.value === b.value) return 0;
8712			return a.value > b.value ? 1 : -1;
8713		});
8714
8715		if (this.sorted.reverse == (parser == HtmlTable.Parsers['input-checked'])) data.reverse(true);
8716		this.setRowSort(data, pre);
8717
8718		if (rel) rel.grab(this.body);
8719		this.fireEvent('stateChanged');
8720		return this.fireEvent('sort', [this.body, this.sorted.index]);
8721	},
8722
8723	parseData: function(parser){
8724		return Array.map(this.body.rows, function(row, i){
8725			var value = parser.convert.call(document.id(row.cells[this.sorted.index]));
8726			return {
8727				position: i,
8728				value: value
8729			};
8730		}, this);
8731	},
8732
8733	clearSort: function(){
8734		this.setHeadSort(false);
8735		this.body.getElements('td').removeClass(this.options.classCellSort);
8736	},
8737
8738	reSort: function(){
8739		if (this.sortEnabled) this.sort.call(this, this.sorted.index, this.sorted.reverse);
8740		return this;
8741	},
8742
8743	enableSort: function(){
8744		this.element.addClass(this.options.classSortable);
8745		this.attachSorts(true);
8746		this.setParsers();
8747		this.sortEnabled = true;
8748		return this;
8749	},
8750
8751	disableSort: function(){
8752		this.element.removeClass(this.options.classSortable);
8753		this.attachSorts(false);
8754		this.sortSpans.each(function(span){
8755			span.destroy();
8756		});
8757		this.sortSpans.empty();
8758		this.sortEnabled = false;
8759		return this;
8760	}
8761
8762});
8763
8764HtmlTable.ParserPriority = ['date', 'input-checked', 'input-value', 'float', 'number'];
8765
8766HtmlTable.Parsers = {
8767
8768	'date': {
8769		match: /^\d{2}[-\/ ]\d{2}[-\/ ]\d{2,4}$/,
8770		convert: function(){
8771			var d = Date.parse(this.get('text').stripTags());
8772			return (typeOf(d) == 'date') ? d.format('db') : '';
8773		},
8774		type: 'date'
8775	},
8776	'input-checked': {
8777		match: / type="(radio|checkbox)" /,
8778		convert: function(){
8779			return this.getElement('input').checked;
8780		}
8781	},
8782	'input-value': {
8783		match: /<input/,
8784		convert: function(){
8785			return this.getElement('input').value;
8786		}
8787	},
8788	'number': {
8789		match: /^\d+[^\d.,]*$/,
8790		convert: function(){
8791			return this.get('text').stripTags().toInt();
8792		},
8793		number: true
8794	},
8795	'numberLax': {
8796		match: /^[^\d]+\d+$/,
8797		convert: function(){
8798			return this.get('text').replace(/[^-?^0-9]/, '').stripTags().toInt();
8799		},
8800		number: true
8801	},
8802	'float': {
8803		match: /^[\d]+\.[\d]+/,
8804		convert: function(){
8805			return this.get('text').replace(/[^-?^\d.]/, '').stripTags().toFloat();
8806		},
8807		number: true
8808	},
8809	'floatLax': {
8810		match: /^[^\d]+[\d]+\.[\d]+$/,
8811		convert: function(){
8812			return this.get('text').replace(/[^-?^\d.]/, '').stripTags();
8813		},
8814		number: true
8815	},
8816	'string': {
8817		match: null,
8818		convert: function(){
8819			return this.get('text').stripTags().toLowerCase();
8820		}
8821	},
8822	'title': {
8823		match: null,
8824		convert: function(){
8825			return this.title;
8826		}
8827	}
8828
8829};
8830
8831
8832
8833HtmlTable.defineParsers = function(parsers){
8834	HtmlTable.Parsers = Object.append(HtmlTable.Parsers, parsers);
8835	for (var parser in parsers){
8836		HtmlTable.ParserPriority.unshift(parser);
8837	}
8838};
8839
8840
8841/*
8842---
8843
8844script: Keyboard.js
8845
8846name: Keyboard
8847
8848description: 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.
8849
8850license: MIT-style license
8851
8852authors:
8853  - Perrin Westrich
8854  - Aaron Newton
8855  - Scott Kyle
8856
8857requires:
8858  - Core/Events
8859  - Core/Options
8860  - Core/Element.Event
8861  - Element.Event.Pseudos.Keys
8862
8863provides: [Keyboard]
8864
8865...
8866*/
8867
8868(function(){
8869
8870	var Keyboard = this.Keyboard = new Class({
8871
8872		Extends: Events,
8873
8874		Implements: [Options],
8875
8876		options: {/*
8877			onActivate: function(){},
8878			onDeactivate: function(){},*/
8879			defaultEventType: 'keydown',
8880			active: false,
8881			manager: null,
8882			events: {},
8883			nonParsedEvents: ['activate', 'deactivate', 'onactivate', 'ondeactivate', 'changed', 'onchanged']
8884		},
8885
8886		initialize: function(options){
8887			if (options && options.manager){
8888				this._manager = options.manager;
8889				delete options.manager;
8890			}
8891			this.setOptions(options);
8892			this._setup();
8893		},
8894
8895		addEvent: function(type, fn, internal){
8896			return this.parent(Keyboard.parse(type, this.options.defaultEventType, this.options.nonParsedEvents), fn, internal);
8897		},
8898
8899		removeEvent: function(type, fn){
8900			return this.parent(Keyboard.parse(type, this.options.defaultEventType, this.options.nonParsedEvents), fn);
8901		},
8902
8903		toggleActive: function(){
8904			return this[this.isActive() ? 'deactivate' : 'activate']();
8905		},
8906
8907		activate: function(instance){
8908			if (instance){
8909				if (instance.isActive()) return this;
8910				//if we're stealing focus, store the last keyboard to have it so the relinquish command works
8911				if (this._activeKB && instance != this._activeKB){
8912					this.previous = this._activeKB;
8913					this.previous.fireEvent('deactivate');
8914				}
8915				//if we're enabling a child, assign it so that events are now passed to it
8916				this._activeKB = instance.fireEvent('activate');
8917				Keyboard.manager.fireEvent('changed');
8918			} else if (this._manager){
8919				//else we're enabling ourselves, we must ask our parent to do it for us
8920				this._manager.activate(this);
8921			}
8922			return this;
8923		},
8924
8925		isActive: function(){
8926			return this._manager ? (this._manager._activeKB == this) : (Keyboard.manager == this);
8927		},
8928
8929		deactivate: function(instance){
8930			if (instance){
8931				if (instance === this._activeKB){
8932					this._activeKB = null;
8933					instance.fireEvent('deactivate');
8934					Keyboard.manager.fireEvent('changed');
8935				}
8936			} else if (this._manager){
8937				this._manager.deactivate(this);
8938			}
8939			return this;
8940		},
8941
8942		relinquish: function(){
8943			if (this.isActive() && this._manager && this._manager.previous) this._manager.activate(this._manager.previous);
8944			else this.deactivate();
8945			return this;
8946		},
8947
8948		//management logic
8949		manage: function(instance){
8950			if (instance._manager) instance._manager.drop(instance);
8951			this._instances.push(instance);
8952			instance._manager = this;
8953			if (!this._activeKB) this.activate(instance);
8954			return this;
8955		},
8956
8957		drop: function(instance){
8958			instance.relinquish();
8959			this._instances.erase(instance);
8960			if (this._activeKB == instance){
8961				if (this.previous && this._instances.contains(this.previous)) this.activate(this.previous);
8962				else this._activeKB = this._instances[0];
8963			}
8964			return this;
8965		},
8966
8967		trace: function(){
8968			Keyboard.trace(this);
8969		},
8970
8971		each: function(fn){
8972			Keyboard.each(this, fn);
8973		},
8974
8975		/*
8976			PRIVATE METHODS
8977		*/
8978
8979		_instances: [],
8980
8981		_disable: function(instance){
8982			if (this._activeKB == instance) this._activeKB = null;
8983		},
8984
8985		_setup: function(){
8986			this.addEvents(this.options.events);
8987			//if this is the root manager, nothing manages it
8988			if (Keyboard.manager && !this._manager) Keyboard.manager.manage(this);
8989			if (this.options.active) this.activate();
8990			else this.relinquish();
8991		},
8992
8993		_handle: function(event, type){
8994			//Keyboard.stop(event) prevents key propagation
8995			if (event.preventKeyboardPropagation) return;
8996
8997			var bubbles = !!this._manager;
8998			if (bubbles && this._activeKB){
8999				this._activeKB._handle(event, type);
9000				if (event.preventKeyboardPropagation) return;
9001			}
9002			this.fireEvent(type, event);
9003
9004			if (!bubbles && this._activeKB) this._activeKB._handle(event, type);
9005		}
9006
9007	});
9008
9009	var parsed = {};
9010	var modifiers = ['shift', 'control', 'alt', 'meta'];
9011	var regex = /^(?:shift|control|ctrl|alt|meta)$/;
9012
9013	Keyboard.parse = function(type, eventType, ignore){
9014		if (ignore && ignore.contains(type.toLowerCase())) return type;
9015
9016		type = type.toLowerCase().replace(/^(keyup|keydown):/, function($0, $1){
9017			eventType = $1;
9018			return '';
9019		});
9020
9021		if (!parsed[type]){
9022			var key, mods = {};
9023			type.split('+').each(function(part){
9024				if (regex.test(part)) mods[part] = true;
9025				else key = part;
9026			});
9027
9028			mods.control = mods.control || mods.ctrl; // allow both control and ctrl
9029
9030			var keys = [];
9031			modifiers.each(function(mod){
9032				if (mods[mod]) keys.push(mod);
9033			});
9034
9035			if (key) keys.push(key);
9036			parsed[type] = keys.join('+');
9037		}
9038
9039		return eventType + ':keys(' + parsed[type] + ')';
9040	};
9041
9042	Keyboard.each = function(keyboard, fn){
9043		var current = keyboard || Keyboard.manager;
9044		while (current){
9045			fn.run(current);
9046			current = current._activeKB;
9047		}
9048	};
9049
9050	Keyboard.stop = function(event){
9051		event.preventKeyboardPropagation = true;
9052	};
9053
9054	Keyboard.manager = new Keyboard({
9055		active: true
9056	});
9057
9058	Keyboard.trace = function(keyboard){
9059		keyboard = keyboard || Keyboard.manager;
9060		var hasConsole = window.console && console.log;
9061		if (hasConsole) console.log('the following items have focus: ');
9062		Keyboard.each(keyboard, function(current){
9063			if (hasConsole) console.log(document.id(current.widget) || current.wiget || current);
9064		});
9065	};
9066
9067	var handler = function(event){
9068		var keys = [];
9069		modifiers.each(function(mod){
9070			if (event[mod]) keys.push(mod);
9071		});
9072
9073		if (!regex.test(event.key)) keys.push(event.key);
9074		Keyboard.manager._handle(event, event.type + ':keys(' + keys.join('+') + ')');
9075	};
9076
9077	document.addEvents({
9078		'keyup': handler,
9079		'keydown': handler
9080	});
9081
9082})();
9083
9084
9085/*
9086---
9087
9088script: Keyboard.Extras.js
9089
9090name: Keyboard.Extras
9091
9092description: 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.
9093
9094license: MIT-style license
9095
9096authors:
9097  - Perrin Westrich
9098
9099requires:
9100  - /Keyboard
9101  - /MooTools.More
9102
9103provides: [Keyboard.Extras]
9104
9105...
9106*/
9107Keyboard.prototype.options.nonParsedEvents.combine(['rebound', 'onrebound']);
9108
9109Keyboard.implement({
9110
9111	/*
9112		shortcut should be in the format of:
9113		{
9114			'keys': 'shift+s', // the default to add as an event.
9115			'description': 'blah blah blah', // a brief description of the functionality.
9116			'handler': function(){} // the event handler to run when keys are pressed.
9117		}
9118	*/
9119	addShortcut: function(name, shortcut){
9120		this._shortcuts = this._shortcuts || [];
9121		this._shortcutIndex = this._shortcutIndex || {};
9122
9123		shortcut.getKeyboard = Function.from(this);
9124		shortcut.name = name;
9125		this._shortcutIndex[name] = shortcut;
9126		this._shortcuts.push(shortcut);
9127		if (shortcut.keys) this.addEvent(shortcut.keys, shortcut.handler);
9128		return this;
9129	},
9130
9131	addShortcuts: function(obj){
9132		for (var name in obj) this.addShortcut(name, obj[name]);
9133		return this;
9134	},
9135
9136	removeShortcut: function(name){
9137		var shortcut = this.getShortcut(name);
9138		if (shortcut && shortcut.keys){
9139			this.removeEvent(shortcut.keys, shortcut.handler);
9140			delete this._shortcutIndex[name];
9141			this._shortcuts.erase(shortcut);
9142		}
9143		return this;
9144	},
9145
9146	removeShortcuts: function(names){
9147		names.each(this.removeShortcut, this);
9148		return this;
9149	},
9150
9151	getShortcuts: function(){
9152		return this._shortcuts || [];
9153	},
9154
9155	getShortcut: function(name){
9156		return (this._shortcutIndex || {})[name];
9157	}
9158
9159});
9160
9161Keyboard.rebind = function(newKeys, shortcuts){
9162	Array.from(shortcuts).each(function(shortcut){
9163		shortcut.getKeyboard().removeEvent(shortcut.keys, shortcut.handler);
9164		shortcut.getKeyboard().addEvent(newKeys, shortcut.handler);
9165		shortcut.keys = newKeys;
9166		shortcut.getKeyboard().fireEvent('rebound');
9167	});
9168};
9169
9170
9171Keyboard.getActiveShortcuts = function(keyboard){
9172	var activeKBS = [], activeSCS = [];
9173	Keyboard.each(keyboard, [].push.bind(activeKBS));
9174	activeKBS.each(function(kb){ activeSCS.extend(kb.getShortcuts()); });
9175	return activeSCS;
9176};
9177
9178Keyboard.getShortcut = function(name, keyboard, opts){
9179	opts = opts || {};
9180	var shortcuts = opts.many ? [] : null,
9181		set = opts.many ? function(kb){
9182				var shortcut = kb.getShortcut(name);
9183				if (shortcut) shortcuts.push(shortcut);
9184			} : function(kb){
9185				if (!shortcuts) shortcuts = kb.getShortcut(name);
9186			};
9187	Keyboard.each(keyboard, set);
9188	return shortcuts;
9189};
9190
9191Keyboard.getShortcuts = function(name, keyboard){
9192	return Keyboard.getShortcut(name, keyboard, { many: true });
9193};
9194
9195
9196/*
9197---
9198
9199script: HtmlTable.Select.js
9200
9201name: HtmlTable.Select
9202
9203description: Builds a stripy, sortable table with methods to add rows. Rows can be selected with the mouse or keyboard navigation.
9204
9205license: MIT-style license
9206
9207authors:
9208  - Harald Kirschner
9209  - Aaron Newton
9210
9211requires:
9212  - /Keyboard
9213  - /Keyboard.Extras
9214  - /HtmlTable
9215  - /Class.refactor
9216  - /Element.Delegation
9217  - /Element.Shortcuts
9218
9219provides: [HtmlTable.Select]
9220
9221...
9222*/
9223
9224HtmlTable = Class.refactor(HtmlTable, {
9225
9226	options: {
9227		/*onRowFocus: function(){},
9228		onRowUnfocus: function(){},*/
9229		useKeyboard: true,
9230		classRowSelected: 'table-tr-selected',
9231		classRowHovered: 'table-tr-hovered',
9232		classSelectable: 'table-selectable',
9233		shiftForMultiSelect: true,
9234		allowMultiSelect: true,
9235		selectable: false,
9236		selectHiddenRows: false
9237	},
9238
9239	initialize: function(){
9240		this.previous.apply(this, arguments);
9241		if (this.occluded) return this.occluded;
9242
9243		this.selectedRows = new Elements();
9244
9245		if (!this.bound) this.bound = {};
9246		this.bound.mouseleave = this.mouseleave.bind(this);
9247		this.bound.clickRow = this.clickRow.bind(this);
9248		this.bound.activateKeyboard = function(){
9249			if (this.keyboard && this.selectEnabled) this.keyboard.activate();
9250		}.bind(this);
9251
9252		if (this.options.selectable) this.enableSelect();
9253	},
9254
9255	empty: function(){
9256		this.selectNone();
9257		return this.previous();
9258	},
9259
9260	enableSelect: function(){
9261		this.selectEnabled = true;
9262		this.attachSelects();
9263		this.element.addClass(this.options.classSelectable);
9264		return this;
9265	},
9266
9267	disableSelect: function(){
9268		this.selectEnabled = false;
9269		this.attachSelects(false);
9270		this.element.removeClass(this.options.classSelectable);
9271		return this;
9272	},
9273
9274	push: function(){
9275		var ret = this.previous.apply(this, arguments);
9276		this.updateSelects();
9277		return ret;
9278	},
9279
9280	toggleRow: function(row){
9281		return this[(this.isSelected(row) ? 'de' : '') + 'selectRow'](row);
9282	},
9283
9284	selectRow: function(row, _nocheck){
9285		//private variable _nocheck: boolean whether or not to confirm the row is in the table body
9286		//added here for optimization when selecting ranges
9287		if (this.isSelected(row) || (!_nocheck && !this.body.getChildren().contains(row))) return;
9288		if (!this.options.allowMultiSelect) this.selectNone();
9289
9290		if (!this.isSelected(row)){
9291			this.selectedRows.push(row);
9292			row.addClass(this.options.classRowSelected);
9293			this.fireEvent('rowFocus', [row, this.selectedRows]);
9294			this.fireEvent('stateChanged');
9295		}
9296
9297		this.focused = row;
9298		document.clearSelection();
9299
9300		return this;
9301	},
9302
9303	isSelected: function(row){
9304		return this.selectedRows.contains(row);
9305	},
9306
9307	getSelected: function(){
9308		return this.selectedRows;
9309	},
9310
9311	getSelected: function(){
9312		return this.selectedRows;
9313	},
9314
9315	serialize: function(){
9316		var previousSerialization = this.previous.apply(this, arguments) || {};
9317		if (this.options.selectable){
9318			previousSerialization.selectedRows = this.selectedRows.map(function(row){
9319				return Array.indexOf(this.body.rows, row);
9320			}.bind(this));
9321		}
9322		return previousSerialization;
9323	},
9324
9325	restore: function(tableState){
9326		if (this.options.selectable && tableState.selectedRows){
9327			tableState.selectedRows.each(function(index){
9328				this.selectRow(this.body.rows[index]);
9329			}.bind(this));
9330		}
9331		this.previous.apply(this, arguments);
9332	},
9333
9334	deselectRow: function(row, _nocheck){
9335		if (!this.isSelected(row) || (!_nocheck && !this.body.getChildren().contains(row))) return;
9336
9337		this.selectedRows = new Elements(Array.from(this.selectedRows).erase(row));
9338		row.removeClass(this.options.classRowSelected);
9339		this.fireEvent('rowUnfocus', [row, this.selectedRows]);
9340		this.fireEvent('stateChanged');
9341		return this;
9342	},
9343
9344	selectAll: function(selectNone){
9345		if (!selectNone && !this.options.allowMultiSelect) return;
9346		this.selectRange(0, this.body.rows.length, selectNone);
9347		return this;
9348	},
9349
9350	selectNone: function(){
9351		return this.selectAll(true);
9352	},
9353
9354	selectRange: function(startRow, endRow, _deselect){
9355		if (!this.options.allowMultiSelect && !_deselect) return;
9356		var method = _deselect ? 'deselectRow' : 'selectRow',
9357			rows = Array.clone(this.body.rows);
9358
9359		if (typeOf(startRow) == 'element') startRow = rows.indexOf(startRow);
9360		if (typeOf(endRow) == 'element') endRow = rows.indexOf(endRow);
9361		endRow = endRow < rows.length - 1 ? endRow : rows.length - 1;
9362
9363		if (endRow < startRow){
9364			var tmp = startRow;
9365			startRow = endRow;
9366			endRow = tmp;
9367		}
9368
9369		for (var i = startRow; i <= endRow; i++){
9370			if (this.options.selectHiddenRows || rows[i].isDisplayed()) this[method](rows[i], true);
9371		}
9372
9373		return this;
9374	},
9375
9376	deselectRange: function(startRow, endRow){
9377		this.selectRange(startRow, endRow, true);
9378	},
9379
9380	getSelected: function(){
9381		return this.selectedRows;
9382	},
9383
9384/*
9385	Private methods:
9386*/
9387
9388	enterRow: function(row){
9389		if (this.hovered) this.hovered = this.leaveRow(this.hovered);
9390		this.hovered = row.addClass(this.options.classRowHovered);
9391	},
9392
9393	leaveRow: function(row){
9394		row.removeClass(this.options.classRowHovered);
9395	},
9396
9397	updateSelects: function(){
9398		Array.each(this.body.rows, function(row){
9399			var binders = row.retrieve('binders');
9400			if (!binders && !this.selectEnabled) return;
9401			if (!binders){
9402				binders = {
9403					mouseenter: this.enterRow.pass([row], this),
9404					mouseleave: this.leaveRow.pass([row], this)
9405				};
9406				row.store('binders', binders);
9407			}
9408			if (this.selectEnabled) row.addEvents(binders);
9409			else row.removeEvents(binders);
9410		}, this);
9411	},
9412
9413	shiftFocus: function(offset, event){
9414		if (!this.focused) return this.selectRow(this.body.rows[0], event);
9415		var to = this.getRowByOffset(offset, this.options.selectHiddenRows);
9416		if (to === null || this.focused == this.body.rows[to]) return this;
9417		this.toggleRow(this.body.rows[to], event);
9418	},
9419
9420	clickRow: function(event, row){
9421		var selecting = (event.shift || event.meta || event.control) && this.options.shiftForMultiSelect;
9422		if (!selecting && !(event.rightClick && this.isSelected(row) && this.options.allowMultiSelect)) this.selectNone();
9423
9424		if (event.rightClick) this.selectRow(row);
9425		else this.toggleRow(row);
9426
9427		if (event.shift){
9428			this.selectRange(this.rangeStart || this.body.rows[0], row, this.rangeStart ? !this.isSelected(row) : true);
9429			this.focused = row;
9430		}
9431		this.rangeStart = row;
9432	},
9433
9434	getRowByOffset: function(offset, includeHiddenRows){
9435		if (!this.focused) return 0;
9436		var index = Array.indexOf(this.body.rows, this.focused);
9437		if ((index == 0 && offset < 0) || (index == this.body.rows.length -1 && offset > 0)) return null;
9438		if (includeHiddenRows){
9439			index += offset;
9440		} else {
9441			var limit = 0,
9442			    count = 0;
9443			if (offset > 0){
9444				while (count < offset && index < this.body.rows.length -1){
9445					if (this.body.rows[++index].isDisplayed()) count++;
9446				}
9447			} else {
9448				while (count > offset && index > 0){
9449					if (this.body.rows[--index].isDisplayed()) count--;
9450				}
9451			}
9452		}
9453		return index;
9454	},
9455
9456	attachSelects: function(attach){
9457		attach = attach != null ? attach : true;
9458
9459		var method = attach ? 'addEvents' : 'removeEvents';
9460		this.element[method]({
9461			mouseleave: this.bound.mouseleave,
9462			click: this.bound.activateKeyboard
9463		});
9464
9465		this.body[method]({
9466			'click:relay(tr)': this.bound.clickRow,
9467			'contextmenu:relay(tr)': this.bound.clickRow
9468		});
9469
9470		if (this.options.useKeyboard || this.keyboard){
9471			if (!this.keyboard) this.keyboard = new Keyboard();
9472			if (!this.selectKeysDefined){
9473				this.selectKeysDefined = true;
9474				var timer, held;
9475
9476				var move = function(offset){
9477					var mover = function(e){
9478						clearTimeout(timer);
9479						e.preventDefault();
9480						var to = this.body.rows[this.getRowByOffset(offset, this.options.selectHiddenRows)];
9481						if (e.shift && to && this.isSelected(to)){
9482							this.deselectRow(this.focused);
9483							this.focused = to;
9484						} else {
9485							if (to && (!this.options.allowMultiSelect || !e.shift)){
9486								this.selectNone();
9487							}
9488							this.shiftFocus(offset, e);
9489						}
9490
9491						if (held){
9492							timer = mover.delay(100, this, e);
9493						} else {
9494							timer = (function(){
9495								held = true;
9496								mover(e);
9497							}).delay(400);
9498						}
9499					}.bind(this);
9500					return mover;
9501				}.bind(this);
9502
9503				var clear = function(){
9504					clearTimeout(timer);
9505					held = false;
9506				};
9507
9508				this.keyboard.addEvents({
9509					'keydown:shift+up': move(-1),
9510					'keydown:shift+down': move(1),
9511					'keyup:shift+up': clear,
9512					'keyup:shift+down': clear,
9513					'keyup:up': clear,
9514					'keyup:down': clear
9515				});
9516
9517				var shiftHint = '';
9518				if (this.options.allowMultiSelect && this.options.shiftForMultiSelect && this.options.useKeyboard){
9519					shiftHint = " (Shift multi-selects).";
9520				}
9521
9522				this.keyboard.addShortcuts({
9523					'Select Previous Row': {
9524						keys: 'up',
9525						shortcut: 'up arrow',
9526						handler: move(-1),
9527						description: 'Select the previous row in the table.' + shiftHint
9528					},
9529					'Select Next Row': {
9530						keys: 'down',
9531						shortcut: 'down arrow',
9532						handler: move(1),
9533						description: 'Select the next row in the table.' + shiftHint
9534					}
9535				});
9536
9537			}
9538			this.keyboard[attach ? 'activate' : 'deactivate']();
9539		}
9540		this.updateSelects();
9541	},
9542
9543	mouseleave: function(){
9544		if (this.hovered) this.leaveRow(this.hovered);
9545	}
9546
9547});
9548
9549
9550/*
9551---
9552
9553script: Scroller.js
9554
9555name: Scroller
9556
9557description: Class which scrolls the contents of any Element (including the window) when the mouse reaches the Element's boundaries.
9558
9559license: MIT-style license
9560
9561authors:
9562  - Valerio Proietti
9563
9564requires:
9565  - Core/Events
9566  - Core/Options
9567  - Core/Element.Event
9568  - Core/Element.Dimensions
9569  - MooTools.More
9570
9571provides: [Scroller]
9572
9573...
9574*/
9575
9576var Scroller = new Class({
9577
9578	Implements: [Events, Options],
9579
9580	options: {
9581		area: 20,
9582		velocity: 1,
9583		onChange: function(x, y){
9584			this.element.scrollTo(x, y);
9585		},
9586		fps: 50
9587	},
9588
9589	initialize: function(element, options){
9590		this.setOptions(options);
9591		this.element = document.id(element);
9592		this.docBody = document.id(this.element.getDocument().body);
9593		this.listener = (typeOf(this.element) != 'element') ? this.docBody : this.element;
9594		this.timer = null;
9595		this.bound = {
9596			attach: this.attach.bind(this),
9597			detach: this.detach.bind(this),
9598			getCoords: this.getCoords.bind(this)
9599		};
9600	},
9601
9602	start: function(){
9603		this.listener.addEvents({
9604			mouseover: this.bound.attach,
9605			mouseleave: this.bound.detach
9606		});
9607		return this;
9608	},
9609
9610	stop: function(){
9611		this.listener.removeEvents({
9612			mouseover: this.bound.attach,
9613			mouseleave: this.bound.detach
9614		});
9615		this.detach();
9616		this.timer = clearInterval(this.timer);
9617		return this;
9618	},
9619
9620	attach: function(){
9621		this.listener.addEvent('mousemove', this.bound.getCoords);
9622	},
9623
9624	detach: function(){
9625		this.listener.removeEvent('mousemove', this.bound.getCoords);
9626		this.timer = clearInterval(this.timer);
9627	},
9628
9629	getCoords: function(event){
9630		this.page = (this.listener.get('tag') == 'body') ? event.client : event.page;
9631		if (!this.timer) this.timer = this.scroll.periodical(Math.round(1000 / this.options.fps), this);
9632	},
9633
9634	scroll: function(){
9635		var size = this.element.getSize(),
9636			scroll = this.element.getScroll(),
9637			pos = this.element != this.docBody ? this.element.getOffsets() : {x: 0, y:0},
9638			scrollSize = this.element.getScrollSize(),
9639			change = {x: 0, y: 0},
9640			top = this.options.area.top || this.options.area,
9641			bottom = this.options.area.bottom || this.options.area;
9642		for (var z in this.page){
9643			if (this.page[z] < (top + pos[z]) && scroll[z] != 0){
9644				change[z] = (this.page[z] - top - pos[z]) * this.options.velocity;
9645			} else if (this.page[z] + bottom > (size[z] + pos[z]) && scroll[z] + size[z] != scrollSize[z]){
9646				change[z] = (this.page[z] - size[z] + bottom - pos[z]) * this.options.velocity;
9647			}
9648			change[z] = change[z].round();
9649		}
9650		if (change.y || change.x) this.fireEvent('change', [scroll.x + change.x, scroll.y + change.y]);
9651	}
9652
9653});
9654
9655
9656/*
9657---
9658
9659script: Tips.js
9660
9661name: Tips
9662
9663description: Class for creating nice tips that follow the mouse cursor when hovering an element.
9664
9665license: MIT-style license
9666
9667authors:
9668  - Valerio Proietti
9669  - Christoph Pojer
9670  - Luis Merino
9671
9672requires:
9673  - Core/Options
9674  - Core/Events
9675  - Core/Element.Event
9676  - Core/Element.Style
9677  - Core/Element.Dimensions
9678  - /MooTools.More
9679
9680provides: [Tips]
9681
9682...
9683*/
9684
9685(function(){
9686
9687var read = function(option, element){
9688	return (option) ? (typeOf(option) == 'function' ? option(element) : element.get(option)) : '';
9689};
9690
9691this.Tips = new Class({
9692
9693	Implements: [Events, Options],
9694
9695	options: {/*
9696		id: null,
9697		onAttach: function(element){},
9698		onDetach: function(element){},
9699		onBound: function(coords){},*/
9700		onShow: function(){
9701			this.tip.setStyle('display', 'block');
9702		},
9703		onHide: function(){
9704			this.tip.setStyle('display', 'none');
9705		},
9706		title: 'title',
9707		text: function(element){
9708			return element.get('rel') || element.get('href');
9709		},
9710		showDelay: 100,
9711		hideDelay: 100,
9712		className: 'tip-wrap',
9713		offset: {x: 16, y: 16},
9714		windowPadding: {x:0, y:0},
9715		fixed: false,
9716		waiAria: true
9717	},
9718
9719	initialize: function(){
9720		var params = Array.link(arguments, {
9721			options: Type.isObject,
9722			elements: function(obj){
9723				return obj != null;
9724			}
9725		});
9726		this.setOptions(params.options);
9727		if (params.elements) this.attach(params.elements);
9728		this.container = new Element('div', {'class': 'tip'});
9729
9730		if (this.options.id){
9731			this.container.set('id', this.options.id);
9732			if (this.options.waiAria) this.attachWaiAria();
9733		}
9734	},
9735
9736	toElement: function(){
9737		if (this.tip) return this.tip;
9738
9739		this.tip = new Element('div', {
9740			'class': this.options.className,
9741			styles: {
9742				position: 'absolute',
9743				top: 0,
9744				left: 0
9745			}
9746		}).adopt(
9747			new Element('div', {'class': 'tip-top'}),
9748			this.container,
9749			new Element('div', {'class': 'tip-bottom'})
9750		);
9751
9752		return this.tip;
9753	},
9754
9755	attachWaiAria: function(){
9756		var id = this.options.id;
9757		this.container.set('role', 'tooltip');
9758
9759		if (!this.waiAria){
9760			this.waiAria = {
9761				show: function(element){
9762					if (id) element.set('aria-describedby', id);
9763					this.container.set('aria-hidden', 'false');
9764				},
9765				hide: function(element){
9766					if (id) element.erase('aria-describedby');
9767					this.container.set('aria-hidden', 'true');
9768				}
9769			};
9770		}
9771		this.addEvents(this.waiAria);
9772	},
9773
9774	detachWaiAria: function(){
9775		if (this.waiAria){
9776			this.container.erase('role');
9777			this.container.erase('aria-hidden');
9778			this.removeEvents(this.waiAria);
9779		}
9780	},
9781
9782	attach: function(elements){
9783		$$(elements).each(function(element){
9784			var title = read(this.options.title, element),
9785				text = read(this.options.text, element);
9786
9787			element.set('title', '').store('tip:native', title).retrieve('tip:title', title);
9788			element.retrieve('tip:text', text);
9789			this.fireEvent('attach', [element]);
9790
9791			var events = ['enter', 'leave'];
9792			if (!this.options.fixed) events.push('move');
9793
9794			events.each(function(value){
9795				var event = element.retrieve('tip:' + value);
9796				if (!event) event = function(event){
9797					this['element' + value.capitalize()].apply(this, [event, element]);
9798				}.bind(this);
9799
9800				element.store('tip:' + value, event).addEvent('mouse' + value, event);
9801			}, this);
9802		}, this);
9803
9804		return this;
9805	},
9806
9807	detach: function(elements){
9808		$$(elements).each(function(element){
9809			['enter', 'leave', 'move'].each(function(value){
9810				element.removeEvent('mouse' + value, element.retrieve('tip:' + value)).eliminate('tip:' + value);
9811			});
9812
9813			this.fireEvent('detach', [element]);
9814
9815			if (this.options.title == 'title'){ // This is necessary to check if we can revert the title
9816				var original = element.retrieve('tip:native');
9817				if (original) element.set('title', original);
9818			}
9819		}, this);
9820
9821		return this;
9822	},
9823
9824	elementEnter: function(event, element){
9825		clearTimeout(this.timer);
9826		this.timer = (function(){
9827			this.container.empty();
9828
9829			['title', 'text'].each(function(value){
9830				var content = element.retrieve('tip:' + value);
9831				var div = this['_' + value + 'Element'] = new Element('div', {
9832						'class': 'tip-' + value
9833					}).inject(this.container);
9834				if (content) this.fill(div, content);
9835			}, this);
9836			this.show(element);
9837			this.position((this.options.fixed) ? {page: element.getPosition()} : event);
9838		}).delay(this.options.showDelay, this);
9839	},
9840
9841	elementLeave: function(event, element){
9842		clearTimeout(this.timer);
9843		this.timer = this.hide.delay(this.options.hideDelay, this, element);
9844		this.fireForParent(event, element);
9845	},
9846
9847	setTitle: function(title){
9848		if (this._titleElement){
9849			this._titleElement.empty();
9850			this.fill(this._titleElement, title);
9851		}
9852		return this;
9853	},
9854
9855	setText: function(text){
9856		if (this._textElement){
9857			this._textElement.empty();
9858			this.fill(this._textElement, text);
9859		}
9860		return this;
9861	},
9862
9863	fireForParent: function(event, element){
9864		element = element.getParent();
9865		if (!element || element == document.body) return;
9866		if (element.retrieve('tip:enter')) element.fireEvent('mouseenter', event);
9867		else this.fireForParent(event, element);
9868	},
9869
9870	elementMove: function(event, element){
9871		this.position(event);
9872	},
9873
9874	position: function(event){
9875		if (!this.tip) document.id(this);
9876
9877		var size = window.getSize(), scroll = window.getScroll(),
9878			tip = {x: this.tip.offsetWidth, y: this.tip.offsetHeight},
9879			props = {x: 'left', y: 'top'},
9880			bounds = {y: false, x2: false, y2: false, x: false},
9881			obj = {};
9882
9883		for (var z in props){
9884			obj[props[z]] = event.page[z] + this.options.offset[z];
9885			if (obj[props[z]] < 0) bounds[z] = true;
9886			if ((obj[props[z]] + tip[z] - scroll[z]) > size[z] - this.options.windowPadding[z]){
9887				obj[props[z]] = event.page[z] - this.options.offset[z] - tip[z];
9888				bounds[z+'2'] = true;
9889			}
9890		}
9891
9892		this.fireEvent('bound', bounds);
9893		this.tip.setStyles(obj);
9894	},
9895
9896	fill: function(element, contents){
9897		if (typeof contents == 'string') element.set('html', contents);
9898		else element.adopt(contents);
9899	},
9900
9901	show: function(element){
9902		if (!this.tip) document.id(this);
9903		if (!this.tip.getParent()) this.tip.inject(document.body);
9904		this.fireEvent('show', [this.tip, element]);
9905	},
9906
9907	hide: function(element){
9908		if (!this.tip) document.id(this);
9909		this.fireEvent('hide', [this.tip, element]);
9910	}
9911
9912});
9913
9914})();
9915
9916
9917/*
9918---
9919
9920script: Locale.Set.From.js
9921
9922name: Locale.Set.From
9923
9924description: Provides an alternative way to create Locale.Set objects.
9925
9926license: MIT-style license
9927
9928authors:
9929  - Tim Wienk
9930
9931requires:
9932  - Core/JSON
9933  - /Locale
9934
9935provides: Locale.Set.From
9936
9937...
9938*/
9939
9940(function(){
9941
9942var parsers = {
9943	'json': JSON.decode
9944};
9945
9946Locale.Set.defineParser = function(name, fn){
9947	parsers[name] = fn;
9948};
9949
9950Locale.Set.from = function(set, type){
9951	if (instanceOf(set, Locale.Set)) return set;
9952
9953	if (!type && typeOf(set) == 'string') type = 'json';
9954	if (parsers[type]) set = parsers[type](set);
9955
9956	var locale = new Locale.Set;
9957
9958	locale.sets = set.sets || {};
9959
9960	if (set.inherits){
9961		locale.inherits.locales = Array.from(set.inherits.locales);
9962		locale.inherits.sets = set.inherits.sets || {};
9963	}
9964
9965	return locale;
9966};
9967
9968})();
9969
9970
9971/*
9972---
9973
9974name: Locale.ar.Date
9975
9976description: Date messages for Arabic.
9977
9978license: MIT-style license
9979
9980authors:
9981  - Chafik Barbar
9982
9983requires:
9984  - /Locale
9985
9986provides: [Locale.ar.Date]
9987
9988...
9989*/
9990
9991Locale.define('ar', 'Date', {
9992
9993	// Culture's date order: DD/MM/YYYY
9994	dateOrder: ['date', 'month', 'year'],
9995	shortDate: '%d/%m/%Y',
9996	shortTime: '%H:%M'
9997
9998});
9999
10000
10001/*
10002---
10003
10004name: Locale.ar.Form.Validator
10005
10006description: Form Validator messages for Arabic.
10007
10008license: MIT-style license
10009
10010authors:
10011  - Chafik Barbar
10012
10013requires:
10014  - /Locale
10015
10016provides: [Locale.ar.Form.Validator]
10017
10018...
10019*/
10020
10021Locale.define('ar', 'FormValidator', {
10022
10023	required: 'هذا الحقل مطلوب.',
10024	minLength: 'رجاءً إدخال {minLength} أحرف على الأقل (تم إدخال {length} أحرف).',
10025	maxLength: 'الرجاء عدم إدخال أكثر من {maxLength} أحرف (تم إدخال {length} أحرف).',
10026	integer: 'الرجاء إدخال عدد صحيح في هذا الحقل. أي رقم ذو كسر عشري أو مئوي (مثال 1.25 ) غير مسموح.',
10027	numeric: 'الرجاء إدخال قيم رقمية في هذا الحقل (مثال "1" أو "1.1" أو "-1" أو "-1.1").',
10028	digits: 'الرجاء أستخدام قيم رقمية وعلامات ترقيمية فقط في هذا الحقل (مثال, رقم هاتف مع نقطة أو شحطة)',
10029	alpha: 'الرجاء أستخدام أحرف فقط (ا-ي) في هذا الحقل. أي فراغات أو علامات غير مسموحة.',
10030	alphanum: 'الرجاء أستخدام أحرف فقط (ا-ي) أو أرقام (0-9) فقط في هذا الحقل. أي فراغات أو علامات غير مسموحة.',
10031	dateSuchAs: 'الرجاء إدخال تاريخ صحيح كالتالي {date}',
10032	dateInFormatMDY: 'الرجاء إدخال تاريخ صحيح (مثال, 31-12-1999)',
10033	email: 'الرجاء إدخال بريد إلكتروني صحيح.',
10034	url: 'الرجاء إدخال عنوان إلكتروني صحيح مثل http://www.example.com',
10035	currencyDollar: 'الرجاء إدخال قيمة $ صحيحة. مثال, 100.00$',
10036	oneRequired: 'الرجاء إدخال قيمة في أحد هذه الحقول على الأقل.',
10037	errorPrefix: 'خطأ: ',
10038	warningPrefix: 'تحذير: '
10039
10040});
10041
10042
10043/*
10044---
10045
10046name: Locale.ca-CA.Date
10047
10048description: Date messages for Catalan.
10049
10050license: MIT-style license
10051
10052authors:
10053  - Ãlfons Sanchez
10054
10055requires:
10056  - /Locale
10057
10058provides: [Locale.ca-CA.Date]
10059
10060...
10061*/
10062
10063Locale.define('ca-CA', 'Date', {
10064
10065	months: ['Gener', 'Febrer', 'Març', 'Abril', 'Maig', 'Juny', 'Juli', 'Agost', 'Setembre', 'Octubre', 'Novembre', 'Desembre'],
10066	months_abbr: ['gen.', 'febr.', 'març', 'abr.', 'maig', 'juny', 'jul.', 'ag.', 'set.', 'oct.', 'nov.', 'des.'],
10067	days: ['Diumenge', 'Dilluns', 'Dimarts', 'Dimecres', 'Dijous', 'Divendres', 'Dissabte'],
10068	days_abbr: ['dg', 'dl', 'dt', 'dc', 'dj', 'dv', 'ds'],
10069
10070	// Culture's date order: DD/MM/YYYY
10071	dateOrder: ['date', 'month', 'year'],
10072	shortDate: '%d/%m/%Y',
10073	shortTime: '%H:%M',
10074	AM: 'AM',
10075	PM: 'PM',
10076	firstDayOfWeek: 0,
10077
10078	// Date.Extras
10079	ordinal: '',
10080
10081	lessThanMinuteAgo: 'fa menys d`un minut',
10082	minuteAgo: 'fa un minut',
10083	minutesAgo: 'fa {delta} minuts',
10084	hourAgo: 'fa un hora',
10085	hoursAgo: 'fa unes {delta} hores',
10086	dayAgo: 'fa un dia',
10087	daysAgo: 'fa {delta} dies',
10088
10089	lessThanMinuteUntil: 'menys d`un minut des d`ara',
10090	minuteUntil: 'un minut des d`ara',
10091	minutesUntil: '{delta} minuts des d`ara',
10092	hourUntil: 'un hora des d`ara',
10093	hoursUntil: 'unes {delta} hores des d`ara',
10094	dayUntil: '1 dia des d`ara',
10095	daysUntil: '{delta} dies des d`ara'
10096
10097});
10098
10099
10100/*
10101---
10102
10103name: Locale.ca-CA.Form.Validator
10104
10105description: Form Validator messages for Catalan.
10106
10107license: MIT-style license
10108
10109authors:
10110  - Miquel Hudin
10111  - Ãlfons Sanchez
10112
10113requires:
10114  - /Locale
10115
10116provides: [Locale.ca-CA.Form.Validator]
10117
10118...
10119*/
10120
10121Locale.define('ca-CA', 'FormValidator', {
10122
10123	required: 'Aquest camp es obligatori.',
10124	minLength: 'Per favor introdueix al menys {minLength} caracters (has introduit {length} caracters).',
10125	maxLength: 'Per favor introdueix no mes de {maxLength} caracters (has introduit {length} caracters).',
10126	integer: 'Per favor introdueix un nombre enter en aquest camp. Nombres amb decimals (p.e. 1,25) no estan permesos.',
10127	numeric: 'Per favor introdueix sols valors numerics en aquest camp (p.e. "1" o "1,1" o "-1" o "-1,1").',
10128	digits: 'Per favor usa sols numeros i puntuacio en aquest camp (per exemple, un nombre de telefon amb guions i punts no esta permes).',
10129	alpha: 'Per favor utilitza lletres nomes (a-z) en aquest camp. No s´admitei
10129xen espais ni altres caracters.',
10130	alphanum: 'Per favor, utilitza nomes lletres (a-z) o numeros (0-9) en aquest camp. No s´admiteixen espais ni altres caracters.',
10131	dateSuchAs: 'Per favor introdueix una data valida com {date}',
10132	dateInFormatMDY: 'Per favor introdueix una data valida com DD/MM/YYYY (p.e. "31/12/1999")',
10133	email: 'Per favor, introdueix una adreça de correu electronic valida. Per exemple, "[email protected]".',
10134	url: 'Per favor introdueix una URL valida com http://www.example.com.',
10135	currencyDollar: 'Per favor introdueix una quantitat valida de €. Per exemple €100,00 .',
10136	oneRequired: 'Per favor introdueix alguna cosa per al menys una d´aquestes entrades.',
10137	errorPrefix: 'Error: ',
10138	warningPrefix: 'Avis: ',
10139
10140	// Form.Validator.Extras
10141	noSpace: 'No poden haver espais en aquesta entrada.',
10142	reqChkByNode: 'No hi han elements seleccionats.',
10143	requiredChk: 'Aquest camp es obligatori.',
10144	reqChkByName: 'Per favor selecciona una {label}.',
10145	match: 'Aquest camp necessita coincidir amb el camp {matchName}',
10146	startDate: 'la data de inici',
10147	endDate: 'la data de fi',
10148	currendDate: 'la data actual',
10149	afterDate: 'La data deu ser igual o posterior a {label}.',
10150	beforeDate: 'La data deu ser igual o anterior a {label}.',
10151	startMonth: 'Per favor selecciona un mes d´orige',
10152	sameMonth: 'Aquestes dos dates deuen estar dins del mateix mes - deus canviar una o altra.'
10153
10154});
10155
10156
10157/*
10158---
10159
10160name: Locale.cs-CZ.Date
10161
10162description: Date messages for Czech.
10163
10164license: MIT-style license
10165
10166authors:
10167  - Jan Černý chemiX
10168  - Christopher Zukowski
10169
10170requires:
10171  - /Locale
10172
10173provides: [Locale.cs-CZ.Date]
10174
10175...
10176*/
10177(function(){
10178
10179// Czech language pluralization rules, see http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
10180// one -> n is 1;            1
10181// few -> n in 2..4;         2-4
10182// other -> everything else  0, 5-999, 1.31, 2.31, 5.31...
10183var pluralize = function (n, one, few, other){
10184	if (n == 1) return one;
10185	else if (n == 2 || n == 3 || n == 4) return few;
10186	else return other;
10187};
10188
10189Locale.define('cs-CZ', 'Date', {
10190
10191	months: ['Leden', 'Únor', 'Březen', 'Duben', 'Květen', 'Červen', 'Červenec', 'Srpen', 'Září', 'Říjen', 'Listopad', 'Prosinec'],
10192	months_abbr: ['ledna', 'února', 'března', 'dubna', 'května', 'června', 'července', 'srpna', 'září', 'října', 'listopadu', 'prosince'],
10193	days: ['Neděle', 'Pondělí', 'Úterý', 'Středa', 'Čtvrtek', 'Pátek', 'Sobota'],
10194	days_abbr: ['ne', 'po', 'út', 'st', 'čt', 'pá', 'so'],
10195
10196	// Culture's date order: DD.MM.YYYY
10197	dateOrder: ['date', 'month', 'year'],
10198	shortDate: '%d.%m.%Y',
10199	shortTime: '%H:%M',
10200	AM: 'dop.',
10201	PM: 'odp.',
10202	firstDayOfWeek: 1,
10203
10204	// Date.Extras
10205	ordinal: '.',
10206
10207	lessThanMinuteAgo: 'před chvílí',
10208	minuteAgo: 'přibližně před minutou',
10209	minutesAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'minutou', 'minutami', 'minutami'); },
10210	hourAgo: 'přibližně před hodinou',
10211	hoursAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'hodinou', 'hodinami', 'hodinami'); },
10212	dayAgo: 'před dnem',
10213	daysAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'dnem', 'dny', 'dny'); },
10214	weekAgo: 'před týdnem',
10215	weeksAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'týdnem', 'týdny', 'týdny'); },
10216	monthAgo: 'před měsícem',
10217	monthsAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'měsícem', 'měsíci', 'měsíci'); },
10218	yearAgo: 'před rokem',
10219	yearsAgo: function(delta){ return 'před {delta} ' + pluralize(delta, 'rokem', 'lety', 'lety'); },
10220
10221	lessThanMinuteUntil: 'za chvíli',
10222	minuteUntil: 'přibližně za minutu',
10223	minutesUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'minutu', 'minuty', 'minut'); },
10224	hourUntil: 'přibližně za hodinu',
10225	hoursUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'hodinu', 'hodiny', 'hodin'); },
10226	dayUntil: 'za den',
10227	daysUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'den', 'dny', 'dnů'); },
10228	weekUntil: 'za týden',
10229	weeksUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'týden', 'týdny', 'týdnů'); },
10230	monthUntil: 'za měsíc',
10231	monthsUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'měsíc', 'měsíce', 'měsíců'); },
10232	yearUntil: 'za rok',
10233	yearsUntil: function(delta){ return 'za {delta} ' + pluralize(delta, 'rok', 'roky', 'let'); }
10234});
10235
10236})();
10237
10238
10239/*
10240---
10241
10242name: Locale.cs-CZ.Form.Validator
10243
10244description: Form Validator messages for Czech.
10245
10246license: MIT-style license
10247
10248authors:
10249  - Jan Černý chemiX
10250
10251requires:
10252  - /Locale
10253
10254provides: [Locale.cs-CZ.Form.Validator]
10255
10256...
10257*/
10258
10259Locale.define('cs-CZ', 'FormValidator', {
10260
10261	required: 'Tato položka je povinná.',
10262	minLength: 'Zadejte prosím alespoň {minLength} znaků (napsáno {length} znaků).',
10263	maxLength: 'Zadejte prosím méně než {maxLength} znaků (nápsáno {length} znaků).',
10264	integer: 'Zadejte prosím celé číslo. Desetinná čísla (např. 1.25) nejsou povolena.',
10265	numeric: 'Zadejte jen číselné hodnoty (tj. "1" nebo "1.1" nebo "-1" nebo "-1.1").',
10266	digits: 'Zadejte prosím pouze čísla a interpunkční znaménka(například telefonní číslo s pomlčkami nebo tečkami je povoleno).',
10267	alpha: 'Zadejte prosím pouze písmena (a-z). Mezery nebo jiné znaky nejsou povoleny.',
10268	alphanum: 'Zadejte prosím pouze písmena (a-z) nebo číslice (0-9). Mezery nebo jiné znaky nejsou povoleny.',
10269	dateSuchAs: 'Zadejte prosím platné datum jako {date}',
10270	dateInFormatMDY: 'Zadejte prosím platné datum jako MM / DD / RRRR (tj. "12/31/1999")',
10271	email: 'Zadejte prosím platnou e-mailovou adresu. Například "[email protected]".',
10272	url: 'Zadejte prosím platnou URL adresu jako http://www.example.com.',
10273	currencyDollar: 'Zadejte prosím platnou částku. Například $100.00.',
10274	oneRequired: 'Zadejte prosím alespoň jednu hodnotu pro tyto položky.',
10275	errorPrefix: 'Chyba: ',
10276	warningPrefix: 'Upozornění: ',
10277
10278	// Form.Validator.Extras
10279	noSpace: 'V této položce nejsou povoleny mezery',
10280	reqChkByNode: 'Nejsou vybrány žádné položky.',
10281	requiredChk: 'Tato položka je vyžadována.',
10282	reqChkByName: 'Prosím vyberte {label}.',
10283	match: 'Tato položka se musí shodovat s položkou {matchName}',
10284	startDate: 'datum zahájení',
10285	endDate: 'datum ukončení',
10286	currendDate: 'aktuální datum',
10287	afterDate: 'Datum by mělo být stejné nebo větší než {label}.',
10288	beforeDate: 'Datum by mělo být stejné nebo menší než {label}.',
10289	startMonth: 'Vyberte počáteční měsíc.',
10290	sameMonth: 'Tyto dva datumy musí být ve stejném měsíci - změňte jeden z nich.',
10291	creditcard: 'Zadané číslo kreditní karty je neplatné. Prosím opravte ho. Bylo zadáno {length} čísel.'
10292
10293});
10294
10295
10296/*
10297---
10298
10299name: Locale.da-DK.Date
10300
10301description: Date messages for Danish.
10302
10303license: MIT-style license
10304
10305authors:
10306  - Martin Overgaard
10307  - Henrik Hansen
10308
10309requires:
10310  - /Locale
10311
10312provides: [Locale.da-DK.Date]
10313
10314...
10315*/
10316
10317Locale.define('da-DK', 'Date', {
10318
10319	months: ['Januar', 'Februar', 'Marts', 'April', 'Maj', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'December'],
10320	months_abbr: ['jan.', 'feb.', 'mar.', 'apr.', 'maj.', 'jun.', 'jul.', 'aug.', 'sep.', 'okt.', 'nov.', 'dec.'],
10321	days: ['Søndag', 'Mandag', 'Tirsdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lørdag'],
10322	days_abbr: ['søn', 'man', 'tir', 'ons', 'tor', 'fre', 'lør'],
10323
10324	// Culture's date order: DD-MM-YYYY
10325	dateOrder: ['date', 'month', 'year'],
10326	shortDate: '%d-%m-%Y',
10327	shortTime: '%H:%M',
10328	AM: 'AM',
10329	PM: 'PM',
10330	firstDayOfWeek: 1,
10331
10332	// Date.Extras
10333	ordinal: '.',
10334
10335	lessThanMinuteAgo: 'mindre end et minut siden',
10336	minuteAgo: 'omkring et minut siden',
10337	minutesAgo: '{delta} minutter siden',
10338	hourAgo: 'omkring en time siden',
10339	hoursAgo: 'omkring {delta} timer siden',
10340	dayAgo: '1 dag siden',
10341	daysAgo: '{delta} dage siden',
10342	weekAgo: '1 uge siden',
10343	weeksAgo: '{delta} uger siden',
10344	monthAgo: '1 måned siden',
10345	monthsAgo: '{delta} måneder siden',
10346	yearAgo: '1 år siden',
10347	yearsAgo: '{delta} år siden',
10348
10349	lessThanMinuteUntil: 'mindre end et minut fra nu',
10350	minuteUntil: 'omkring et minut fra nu',
10351	minutesUntil: '{delta} minutter fra nu',
10352	hourUntil: 'omkring en time fra nu',
10353	hoursUntil: 'omkring {delta} timer fra nu',
10354	dayUntil: '1 dag fra nu',
10355	daysUntil: '{delta} dage fra nu',
10356	weekUntil: '1 uge fra nu',
10357	weeksUntil: '{delta} uger fra nu',
10358	monthUntil: '1 måned fra nu',
10359	monthsUntil: '{delta} måneder fra nu',
10360	yearUntil: '1 år fra nu',
10361	yearsUntil: '{delta} år fra nu'
10362
10363});
10364
10365
10366/*
10367---
10368
10369name: Locale.da-DK.Form.Validator
10370
10371description: Form Validator messages for Danish.
10372
10373license: MIT-style license
10374
10375authors:
10376  - Martin Overgaard
10377
10378requires:
10379  - /Locale
10380
10381provides: [Locale.da-DK.Form.Validator]
10382
10383...
10384*/
10385
10386Locale.define('da-DK', 'FormValidator', {
10387
10388	required: 'Feltet skal udfyldes.',
10389	minLength: 'Skriv mindst {minLength} tegn (du skrev {length} tegn).',
10390	maxLength: 'Skriv maksimalt {maxLength} tegn (du skrev {length} tegn).',
10391	integer: 'Skriv et tal i dette felt. Decimal tal (f.eks. 1.25) er ikke tilladt.',
10392	numeric: 'Skriv kun tal i dette felt (i.e. "1" eller "1.1" eller "-1" eller "-1.1").',
10393	digits: 'Skriv kun tal og tegnsætning i dette felt (eksempel, et telefon nummer med bindestreg eller punktum er tilladt).',
10394	alpha: 'Skriv kun bogstaver (a-z) i dette felt. Mellemrum og andre tegn er ikke tilladt.',
10395	alphanum: 'Skriv kun bogstaver (a-z) eller tal (0-9) i dette felt. Mellemrum og andre tegn er ikke tilladt.',
10396	dateSuchAs: 'Skriv en gyldig dato som {date}',
10397	dateInFormatMDY: 'Skriv dato i formatet DD-MM-YYYY (f.eks. "31-12-1999")',
10398	email: 'Skriv en gyldig e-mail adresse. F.eks "[email protected]".',
10399	url: 'Skriv en gyldig URL adresse. F.eks "http://www.example.com".',
10400	currencyDollar: 'Skriv et gldigt beløb. F.eks Kr.100.00 .',
10401	oneRequired: 'Et eller flere af felterne i denne formular skal udfyldes.',
10402	errorPrefix: 'Fejl: ',
10403	warningPrefix: 'Advarsel: ',
10404
10405	// Form.Validator.Extras
10406	noSpace: 'Der må ikke benyttes mellemrum i dette felt.',
10407	reqChkByNode: 'Foretag et valg.',
10408	requiredChk: 'Dette felt skal udfyldes.',
10409	reqChkByName: 'Vælg en {label}.',
10410	match: 'Dette felt skal matche {matchName} feltet',
10411	startDate: 'start dato',
10412	endDate: 'slut dato',
10413	currendDate: 'dags dato',
10414	afterDate: 'Datoen skal være større end eller lig med {label}.',
10415	beforeDate: 'Datoen skal være mindre end eller lig med {label}.',
10416	startMonth: 'Vælg en start måned',
10417	sameMonth: 'De valgte datoer skal være i samme måned - skift en af dem.'
10418
10419});
10420
10421
10422/*
10423---
10424
10425name: Locale.de-DE.Date
10426
10427description: Date messages for German.
10428
10429license: MIT-style license
10430
10431authors:
10432  - Christoph Pojer
10433  - Frank Rossi
10434  - Ulrich Petri
10435  - Fabian Beiner
10436
10437requires:
10438  - /Locale
10439
10440provides: [Locale.de-DE.Date]
10441
10442...
10443*/
10444
10445Locale.define('de-DE', 'Date', {
10446
10447	months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
10448	months_abbr: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'],
10449	days: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
10450	days_abbr: ['So.', 'Mo.', 'Di.', 'Mi.', 'Do.', 'Fr.', 'Sa.'],
10451
10452	// Culture's date order: DD.MM.YYYY
10453	dateOrder: ['date', 'month', 'year'],
10454	shortDate: '%d.%m.%Y',
10455	shortTime: '%H:%M',
10456	AM: 'vormittags',
10457	PM: 'nachmittags',
10458	firstDayOfWeek: 1,
10459
10460	// Date.Extras
10461	ordinal: '.',
10462
10463	lessThanMinuteAgo: 'vor weniger als einer Minute',
10464	minuteAgo: 'vor einer Minute',
10465	minutesAgo: 'vor {delta} Minuten',
10466	hourAgo: 'vor einer Stunde',
10467	hoursAgo: 'vor {delta} Stunden',
10468	dayAgo: 'vor einem Tag',
10469	daysAgo: 'vor {delta} Tagen',
10470	weekAgo: 'vor einer Woche',
10471	weeksAgo: 'vor {delta} Wochen',
10472	monthAgo: 'vor einem Monat',
10473	monthsAgo: 'vor {delta} Monaten',
10474	yearAgo: 'vor einem Jahr',
10475	yearsAgo: 'vor {delta} Jahren',
10476
10477	lessThanMinuteUntil: 'in weniger als einer Minute',
10478	minuteUntil: 'in einer Minute',
10479	minutesUntil: 'in {delta} Minuten',
10480	hourUntil: 'in ca. einer Stunde',
10481	hoursUntil: 'in ca. {delta} Stunden',
10482	dayUntil: 'in einem Tag',
10483	daysUntil: 'in {delta} Tagen',
10484	weekUntil: 'in einer Woche',
10485	weeksUntil: 'in {delta} Wochen',
10486	monthUntil: 'in einem Monat',
10487	monthsUntil: 'in {delta} Monaten',
10488	yearUntil: 'in einem Jahr',
10489	yearsUntil: 'in {delta} Jahren'
10490
10491});
10492
10493
10494/*
10495---
10496
10497name: Locale.de-CH.Date
10498
10499description: Date messages for German (Switzerland).
10500
10501license: MIT-style license
10502
10503authors:
10504  - Michael van der Weg
10505
10506requires:
10507  - /Locale
10508  - /Locale.de-DE.Date
10509
10510provides: [Locale.de-CH.Date]
10511
10512...
10513*/
10514
10515Locale.define('de-CH').inherit('de-DE', 'Date');
10516
10517
10518/*
10519---
10520
10521name: Locale.de-CH.Form.Validator
10522
10523description: Form Validator messages for German (Switzerland).
10524
10525license: MIT-style license
10526
10527authors:
10528  - Michael van der Weg
10529
10530requires:
10531  - /Locale
10532
10533provides: [Locale.de-CH.Form.Validator]
10534
10535...
10536*/
10537
10538Locale.define('de-CH', 'FormValidator', {
10539
10540	required: 'Dieses Feld ist obligatorisch.',
10541	minLength: 'Geben Sie bitte mindestens {minLength} Zeichen ein (Sie haben {length} Zeichen eingegeben).',
10542	maxLength: 'Bitte geben Sie nicht mehr als {maxLength} Zeichen ein (Sie haben {length} Zeichen eingegeben).',
10543	integer: 'Geben Sie bitte eine ganze Zahl ein. Dezimalzahlen (z.B. 1.25) sind nicht erlaubt.',
10544	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;).',
10545	digits: 'Benutzen Sie bitte nur Zahlen und Satzzeichen in diesem Eingabefeld (erlaubt ist z.B. eine Telefonnummer mit Bindestrichen und Punkten).',
10546	alpha: 'Benutzen Sie bitte nur Buchstaben (a-z) in diesem Feld. Leerzeichen und andere Zeichen sind nicht erlaubt.',
10547	alphanum: 'Benutzen Sie bitte nur Buchstaben (a-z) und Zahlen (0-9) in diesem Eingabefeld. Leerzeichen und andere Zeichen sind nicht erlaubt.',
10548	dateSuchAs: 'Geben Sie bitte ein g&uuml;ltiges Datum ein. Wie zum Beispiel {date}',
10549	dateInFormatMDY: 'Geben Sie bitte ein g&uuml;ltiges Datum ein. Wie zum Beispiel TT.MM.JJJJ (z.B. &quot;31.12.1999&quot;)',
10550	email: 'Geben Sie bitte eine g&uuml;ltige E-Mail Adresse ein. Wie zum Beispiel &quot;[email protected]&quot;.',
10551	url: 'Geben Sie bitte eine g&uuml;ltige URL ein. Wie zum Beispiel http://www.example.com.',
10552	currencyDollar: 'Geben Sie bitte einen g&uuml;ltigen Betrag in Schweizer Franken ein. Wie zum Beispiel 100.00 CHF .',
10553	oneRequired: 'Machen Sie f&uuml;r mindestens eines der Eingabefelder einen Eintrag.',
10554	errorPrefix: 'Fehler: ',
10555	warningPrefix: 'Warnung: ',
10556
10557	// Form.Validator.Extras
10558	noSpace: 'In diesem Eingabefeld darf kein Leerzeichen sein.',
10559	reqChkByNode: 'Es wurden keine Elemente gew&auml;hlt.',
10560	requiredChk: 'Dieses Feld ist obligatorisch.',
10561	reqChkByName: 'Bitte w&auml;hlen Sie ein {label}.',
10562	match: 'Dieses Eingabefeld muss mit dem Feld {matchName} &uuml;bereinstimmen.',
10563	startDate: 'Das Anfangsdatum',
10564	endDate: 'Das Enddatum',
10565	currendDate: 'Das aktuelle Datum',
10566	afterDate: 'Das Datum sollte zur gleichen Zeit oder sp&auml;ter sein {label}.',
10567	beforeDate: 'Das Datum sollte zur gleichen Zeit oder fr&uuml;her sein {label}.',
10568	startMonth: 'W&auml;hlen Sie bitte einen Anfangsmonat',
10569	sameMonth: 'Diese zwei Datumsangaben m&uuml;ssen im selben Monat sein - Sie m&uuml;ssen eine von beiden ver&auml;ndern.',
10570	creditcard: 'Die eingegebene Kreditkartennummer ist ung&uuml;ltig. Bitte &uuml;berpr&uuml;fen Sie diese und versuchen Sie es erneut. {length} Zahlen eingegeben.'
10571
10572}
10572);
10573
10574
10575/*
10576---
10577
10578name: Locale.de-DE.Form.Validator
10579
10580description: Form Validator messages for German.
10581
10582license: MIT-style license
10583
10584authors:
10585  - Frank Rossi
10586  - Ulrich Petri
10587  - Fabian Beiner
10588
10589requires:
10590  - /Locale
10591
10592provides: [Locale.de-DE.Form.Validator]
10593
10594...
10595*/
10596
10597Locale.define('de-DE', 'FormValidator', {
10598
10599	required: 'Dieses Eingabefeld muss ausgefüllt werden.',
10600	minLength: 'Geben Sie bitte mindestens {minLength} Zeichen ein (Sie haben nur {length} Zeichen eingegeben).',
10601	maxLength: 'Geben Sie bitte nicht mehr als {maxLength} Zeichen ein (Sie haben {length} Zeichen eingegeben).',
10602	integer: 'Geben Sie in diesem Eingabefeld bitte eine ganze Zahl ein. Dezimalzahlen (z.B. "1.25") sind nicht erlaubt.',
10603	numeric: 'Geben Sie in diesem Eingabefeld bitte nur Zahlenwerte (z.B. "1", "1.1", "-1" oder "-1.1") ein.',
10604	digits: 'Geben Sie in diesem Eingabefeld bitte nur Zahlen und Satzzeichen ein (z.B. eine Telefonnummer mit Bindestrichen und Punkten ist erlaubt).',
10605	alpha: 'Geben Sie in diesem Eingabefeld bitte nur Buchstaben (a-z) ein. Leerzeichen und andere Zeichen sind nicht erlaubt.',
10606	alphanum: 'Geben Sie in diesem Eingabefeld bitte nur Buchstaben (a-z) und Zahlen (0-9) ein. Leerzeichen oder andere Zeichen sind nicht erlaubt.',
10607	dateSuchAs: 'Geben Sie bitte ein gültiges Datum ein (z.B. "{date}").',
10608	dateInFormatMDY: 'Geben Sie bitte ein gültiges Datum im Format TT.MM.JJJJ ein (z.B. "31.12.1999").',
10609	email: 'Geben Sie bitte eine gültige E-Mail-Adresse ein (z.B. "[email protected]").',
10610	url: 'Geben Sie bitte eine gültige URL ein (z.B. "http://www.example.com").',
10611	currencyDollar: 'Geben Sie bitte einen gültigen Betrag in EURO ein (z.B. 100.00€).',
10612	oneRequired: 'Bitte füllen Sie mindestens ein Eingabefeld aus.',
10613	errorPrefix: 'Fehler: ',
10614	warningPrefix: 'Warnung: ',
10615
10616	// Form.Validator.Extras
10617	noSpace: 'Es darf kein Leerzeichen in diesem Eingabefeld sein.',
10618	reqChkByNode: 'Es wurden keine Elemente gewählt.',
10619	requiredChk: 'Dieses Feld muss ausgefüllt werden.',
10620	reqChkByName: 'Bitte wählen Sie ein {label}.',
10621	match: 'Dieses Eingabefeld muss mit dem {matchName} Eingabefeld übereinstimmen.',
10622	startDate: 'Das Anfangsdatum',
10623	endDate: 'Das Enddatum',
10624	currendDate: 'Das aktuelle Datum',
10625	afterDate: 'Das Datum sollte zur gleichen Zeit oder später sein als {label}.',
10626	beforeDate: 'Das Datum sollte zur gleichen Zeit oder früher sein als {label}.',
10627	startMonth: 'Wählen Sie bitte einen Anfangsmonat',
10628	sameMonth: 'Diese zwei Datumsangaben müssen im selben Monat sein - Sie müssen eines von beiden verändern.',
10629	creditcard: 'Die eingegebene Kreditkartennummer ist ungültig. Bitte überprüfen Sie diese und versuchen Sie es erneut. {length} Zahlen eingegeben.'
10630
10631});
10632
10633
10634/*
10635---
10636
10637name: Locale.EU.Number
10638
10639description: Number messages for Europe.
10640
10641license: MIT-style license
10642
10643authors:
10644  - Arian Stolwijk
10645
10646requires:
10647  - /Locale
10648
10649provides: [Locale.EU.Number]
10650
10651...
10652*/
10653
10654Locale.define('EU', 'Number', {
10655
10656	decimal: ',',
10657	group: '.',
10658
10659	currency: {
10660		prefix: '€ '
10661	}
10662
10663});
10664
10665
10666/*
10667---
10668
10669name: Locale.de-DE.Number
10670
10671description: Number messages for German.
10672
10673license: MIT-style license
10674
10675authors:
10676  - Christoph Pojer
10677
10678requires:
10679  - /Locale
10680  - /Locale.EU.Number
10681
10682provides: [Locale.de-DE.Number]
10683
10684...
10685*/
10686
10687Locale.define('de-DE').inherit('EU', 'Number');
10688
10689
10690/*
10691---
10692
10693name: Locale.en-GB.Date
10694
10695description: Date messages for British English.
10696
10697license: MIT-style license
10698
10699authors:
10700  - Aaron Newton
10701
10702requires:
10703  - /Locale
10704  - /Locale.en-US.Date
10705
10706provides: [Locale.en-GB.Date]
10707
10708...
10709*/
10710
10711Locale.define('en-GB', 'Date', {
10712
10713	// Culture's date order: DD/MM/YYYY
10714	dateOrder: ['date', 'month', 'year'],
10715	shortDate: '%d/%m/%Y',
10716	shortTime: '%H:%M'
10717
10718}).inherit('en-US', 'Date');
10719
10720
10721/*
10722---
10723
10724name: Locale.es-ES.Date
10725
10726description: Date messages for Spanish.
10727
10728license: MIT-style license
10729
10730authors:
10731  - Ãlfons Sanchez
10732
10733requires:
10734  - /Locale
10735
10736provides: [Locale.es-ES.Date]
10737
10738...
10739*/
10740
10741Locale.define('es-ES', 'Date', {
10742
10743	months: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'],
10744	months_abbr: ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic'],
10745	days: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'],
10746	days_abbr: ['dom', 'lun', 'mar', 'mié', 'juv', 'vie', 'sáb'],
10747
10748	// Culture's date order: DD/MM/YYYY
10749	dateOrder: ['date', 'month', 'year'],
10750	shortDate: '%d/%m/%Y',
10751	shortTime: '%H:%M',
10752	AM: 'AM',
10753	PM: 'PM',
10754	firstDayOfWeek: 1,
10755
10756	// Date.Extras
10757	ordinal: '',
10758
10759	lessThanMinuteAgo: 'hace menos de un minuto',
10760	minuteAgo: 'hace un minuto',
10761	minutesAgo: 'hace {delta} minutos',
10762	hourAgo: 'hace una hora',
10763	hoursAgo: 'hace unas {delta} horas',
10764	dayAgo: 'hace un día',
10765	daysAgo: 'hace {delta} días',
10766	weekAgo: 'hace una semana',
10767	weeksAgo: 'hace unas {delta} semanas',
10768	monthAgo: 'hace un mes',
10769	monthsAgo: 'hace {delta} meses',
10770	yearAgo: 'hace un año',
10771	yearsAgo: 'hace {delta} años',
10772
10773	lessThanMinuteUntil: 'menos de un minuto desde ahora',
10774	minuteUntil: 'un minuto desde ahora',
10775	minutesUntil: '{delta} minutos desde ahora',
10776	hourUntil: 'una hora desde ahora',
10777	hoursUntil: 'unas {delta}
10777 horas desde ahora',
10778	dayUntil: 'un día desde ahora',
10779	daysUntil: '{delta} días desde ahora',
10780	weekUntil: 'una semana desde ahora',
10781	weeksUntil: 'unas {delta} semanas desde ahora',
10782	monthUntil: 'un mes desde ahora',
10783	monthsUntil: '{delta} meses desde ahora',
10784	yearUntil: 'un año desde ahora',
10785	yearsUntil: '{delta} años desde ahora'
10786
10787});
10788
10789
10790/*
10791---
10792
10793name: Locale.es-AR.Date
10794
10795description: Date messages for Spanish (Argentina).
10796
10797license: MIT-style license
10798
10799authors:
10800  - Ãlfons Sanchez
10801  - Diego Massanti
10802
10803requires:
10804  - /Locale
10805  - /Locale.es-ES.Date
10806
10807provides: [Locale.es-AR.Date]
10808
10809...
10810*/
10811
10812Locale.define('es-AR').inherit('es-ES', 'Date');
10813
10814
10815/*
10816---
10817
10818name: Locale.es-AR.Form.Validator
10819
10820description: Form Validator messages for Spanish (Argentina).
10821
10822license: MIT-style license
10823
10824authors:
10825  - Diego Massanti
10826
10827requires:
10828  - /Locale
10829
10830provides: [Locale.es-AR.Form.Validator]
10831
10832...
10833*/
10834
10835Locale.define('es-AR', 'FormValidator', {
10836
10837	required: 'Este campo es obligatorio.',
10838	minLength: 'Por favor ingrese al menos {minLength} caracteres (ha ingresado {length} caracteres).',
10839	maxLength: 'Por favor no ingrese más de {maxLength} caracteres (ha ingresado {length} caracteres).',
10840	integer: 'Por favor ingrese un número entero en este campo. Números con decimales (p.e. 1,25) no se permiten.',
10841	numeric: 'Por favor ingrese solo valores numéricos en este campo (p.e. "1" o "1,1" o "-1" o "-1,1").',
10842	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).',
10843	alpha: 'Por favor use sólo letras (a-z) en este campo. No se permiten espacios ni otros caracteres.',
10844	alphanum: 'Por favor, usa sólo letras (a-z) o números (0-9) en este campo. No se permiten espacios u otros caracteres.',
10845	dateSuchAs: 'Por favor ingrese una fecha válida como {date}',
10846	dateInFormatMDY: 'Por favor ingrese una fecha válida, utulizando el formato DD/MM/YYYY (p.e. "31/12/1999")',
10847	email: 'Por favor, ingrese una dirección de e-mail válida. Por ejemplo, "[email protected]".',
10848	url: 'Por favor ingrese una URL válida como http://www.example.com.',
10849	currencyDollar: 'Por favor ingrese una cantidad válida de pesos. Por ejemplo $100,00 .',
10850	oneRequired: 'Por favor ingrese algo para por lo menos una de estas entradas.',
10851	errorPrefix: 'Error: ',
10852	warningPrefix: 'Advertencia: ',
10853
10854	// Form.Validator.Extras
10855	noSpace: 'No se permiten espacios en este campo.',
10856	reqChkByNode: 'No hay elementos seleccionados.',
10857	requiredChk: 'Este campo es obligatorio.',
10858	reqChkByName: 'Por favor selecciona una {label}.',
10859	match: 'Este campo necesita coincidir con el campo {matchName}',
10860	startDate: 'la fecha de inicio',
10861	endDate: 'la fecha de fin',
10862	currendDate: 'la fecha actual',
10863	afterDate: 'La fecha debe ser igual o posterior a {label}.',
10864	beforeDate: 'La fecha debe ser igual o anterior a {label}.',
10865	startMonth: 'Por favor selecciona un mes de origen',
10866	sameMonth: 'Estas dos fechas deben estar en el mismo mes - debes cambiar una u otra.'
10867
10868});
10869
10870
10871/*
10872---
10873
10874name: Locale.es-ES.Form.Validator
10875
10876description: Form Validator messages for Spanish.
10877
10878license: MIT-style license
10879
10880authors:
10881  - Ãlfons Sanchez
10882
10883requires:
10884  - /Locale
10885
10886provides: [Locale.es-ES.Form.Validator]
10887
10888...
10889*/
10890
10891Locale.define('es-ES', 'FormValidator', {
10892
10893	required: 'Este campo es obligatorio.',
10894	minLength: 'Por favor introduce al menos {minLength} caracteres (has introducido {length} caracteres).',
10895	maxLength: 'Por favor introduce no m&aacute;s de {maxLength} caracteres (has introducido {length} caracteres).',
10896	integer: 'Por favor introduce un n&uacute;mero entero en este campo. N&uacute;meros con decimales (p.e. 1,25) no se permiten.',
10897	numeric: 'Por favor introduce solo valores num&eacute;ricos en este campo (p.e. "1" o "1,1" o "-1" o "-1,1").',
10898	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).',
10899	alpha: 'Por favor usa letras solo (a-z) en este campo. No se admiten espacios ni otros caracteres.',
10900	alphanum: 'Por favor, usa solo letras (a-z) o n&uacute;meros (0-9) en este campo. No se admiten espacios ni otros caracteres.',
10901	dateSuchAs: 'Por favor introduce una fecha v&aacute;lida como {date}',
10902	dateInFormatMDY: 'Por favor introduce una fecha v&aacute;lida como DD/MM/YYYY (p.e. "31/12/1999")',
10903	email: 'Por favor, introduce una direcci&oacute;n de email v&aacute;lida. Por ejemplo, "[email protected]".',
10904	url: 'Por favor introduce una URL v&aacute;lida como http://www.example.com.',
10905	currencyDollar: 'Por favor introduce una cantidad v&aacute;lida de €. Por ejemplo €100,00 .',
10906	oneRequired: 'Por favor introduce algo para por lo menos una de estas entradas.',
10907	errorPrefix: 'Error: ',
10908	warningPrefix: 'Aviso: ',
10909
10910	// Form.Validator.Extras
10911	noSpace: 'No pueden haber espacios en esta entrada.',
10912	reqChkByNode: 'No hay elementos seleccionados.',
10913	requiredChk: 'Este campo es obligatorio.',
10914	reqChkByName: 'Por favor selecciona una {label}.',
10915	match: 'Este campo necesita coincidir con el campo {matchName}',
10916	startDate: 'la fecha de inicio',
10917	endDate: 'la fecha de fin',
10918	currendDate: 'la fecha actual',
10919	afterDate: 'La fecha debe ser igual o posterior a {label}.',
10920	beforeDate: 'La fecha debe ser igual o anterior a {label}.',
10921	startMonth: 'Por favor selecciona un mes de origen',
10922	sameMonth: 'Estas dos fechas deben estar en el mismo mes - debes cambiar una u otra.'
10923
10924});
10925
10926
10927/*
10928---
10929
10930name: Locale.et-EE.Date
10931
10932description: Date messages for Estonian.
10933
10934license: MIT-style license
10935
10936authors:
10937  - Kevin Valdek
10938
10939requires:
10940  - /Locale
10941
10942provides: [Locale.et-EE.Date]
10943
10944...
10945*/
10946
10947Locale.define('et-EE', 'Date', {
10948
10949	months: ['jaanuar', 'veebruar', 'märts', 'aprill', 'mai', 'juuni', 'juuli', 'august', 'september', 'oktoober', 'november', 'detsember'],
10950	months_abbr: ['jaan', 'veebr', 'märts', 'apr', 'mai', 'juuni', 'juuli', 'aug', 'sept', 'okt', 'nov', 'dets'],
10951	days: ['pühapäev', 'esmaspäev', 'teisipäev', 'kolmapäev', 'neljapäev', 'reede', 'laupäev'],
10952	days_abbr: ['pühap', 'esmasp', 'teisip', 'kolmap', 'neljap', 'reede', 'laup'],
10953
10954	// Culture's date order: MM.DD.YYYY
10955	dateOrder: ['month', 'date', 'year'],
10956	shortDate: '%m.%d.%Y',
10957	shortTime: '%H:%M',
10958	AM: 'AM',
10959	PM: 'PM',
10960	firstDayOfWeek: 1,
10961
10962	// Date.Extras
10963	ordinal: '',
10964
10965	lessThanMinuteAgo: 'vähem kui minut aega tagasi',
10966	minuteAgo: 'umbes minut aega tagasi',
10967	minutesAgo: '{delta} minutit tagasi',
10968	hourAgo: 'umbes tund aega tagasi',
10969	hoursAgo: 'umbes {delta} tundi tagasi',
10970	dayAgo: '1 päev tagasi',
10971	daysAgo: '{delta} päeva tagasi',
10972	weekAgo: '1 nädal tagasi',
10973	weeksAgo: '{delta} nädalat tagasi',
10974	monthAgo: '1 kuu tagasi',
10975	monthsAgo: '{delta} kuud tagasi',
10976	yearAgo: '1 aasta tagasi',
10977	yearsAgo: '{delta} aastat tagasi',
10978
10979	lessThanMinuteUntil: 'vähem kui minuti aja pärast',
10980	minuteUntil: 'umbes minuti aja pärast',
10981	minutesUntil: '{delta} minuti pärast',
10982	hourUntil: 'umbes tunni aja pärast',
10983	hoursUntil: 'umbes {delta} tunni pärast',
10984	dayUntil: '1 päeva pärast',
10985	daysUntil: '{delta} päeva pärast',
10986	weekUntil: '1 nädala pärast',
10987	weeksUntil: '{delta} nädala pärast',
10988	monthUntil: '1 kuu pärast',
10989	monthsUntil: '{delta} kuu pärast',
10990	yearUntil: '1 aasta pärast',
10991	yearsUntil: '{delta} aasta pärast'
10992
10993});
10994
10995
10996/*
10997---
10998
10999name: Locale.et-EE.Form.Validator
11000
11001description: Form Validator messages for Estonian.
11002
11003license: MIT-style license
11004
11005authors:
11006  - Kevin Valdek
11007
11008requires:
11009  - /Locale
11010
11011provides: [Locale.et-EE.Form.Validator]
11012
11013...
11014*/
11015
11016Locale.define('et-EE', 'FormValidator', {
11017
11018	required: 'Väli peab olema täidetud.',
11019	minLength: 'Palun sisestage vähemalt {minLength} tähte (te sisestasite {length} tähte).',
11020	maxLength: 'Palun ärge sisestage rohkem kui {maxLength} tähte (te sisestasite {length} tähte).',
11021	integer: 'Palun sisestage väljale täisarv. Kümnendarvud (näiteks 1.25) ei ole lubatud.',
11022	numeric: 'Palun sisestage ainult numbreid väljale (näiteks "1", "1.1", "-1" või "-1.1").',
11023	digits: 'Palun kasutage ainult numbreid ja kirjavahemärke (telefoninumbri sisestamisel on lubatud kasutada kriipse ja punkte).',
11024	alpha: 'Palun kasutage ainult tähti (a-z). Tühikud ja teised sümbolid on keelatud.',
11025	alphanum: 'Palun kasutage ainult tähti (a-z) või numbreid (0-9). Tühikud ja teised sümbolid on keelatud.',
11026	dateSuchAs: 'Palun sisestage kehtiv kuupäev kujul {date}',
11027	dateInFormatMDY: 'Palun sisestage kehtiv kuupäev kujul MM.DD.YYYY (näiteks: "12.31.1999").',
11028	email: 'Palun sisestage kehtiv e-maili aadress (näiteks: "[email protected]").',
11029	url: 'Palun sisestage kehtiv URL (näiteks: http://www.example.com).',
11030	currencyDollar: 'Palun sisestage kehtiv $ summa (näiteks: $100.00).',
11031	oneRequired: 'Palun sisestage midagi vähemalt ühele antud väljadest.',
11032	errorPrefix: 'Viga: ',
11033	warningPrefix: 'Hoiatus: ',
11034
11035	// Form.Validator.Extras
11036	noSpace: 'Väli ei tohi sisaldada tühikuid.',
11037	reqChkByNode: 'Ükski väljadest pole valitud.',
11038	requiredChk: 'Välja täitmine on vajalik.',
11039	reqChkByName: 'Palun valige üks {label}.',
11040	match: 'Väli peab sobima {matchName} väljaga',
11041	startDate: 'algkuupäev',
11042	endDate: 'lõppkuupäev',
11043	currendDate: 'praegune kuupäev',
11044	afterDate: 'Kuupäev peab olema võrdne või pärast {label}.',
11045	beforeDate: 'Kuupäev peab olema võrdne või enne {label}.',
11046	startMonth: 'Palun valige algkuupäev.',
11047	sameMonth: 'Antud kaks kuupäeva peavad olema samas kuus - peate muutma ühte kuupäeva.'
11048
11049});
11050
11051
11052/*
11053---
11054
11055name: Locale.fa.Date
11056
11057description: Date messages for Persian.
11058
11059license: MIT-style license
11060
11061authors:
11062  - Amir Hossein Hodjaty Pour
11063
11064requires:
11065  - /Locale
11066
11067provides: [Locale.fa.Date]
11068
11069...
11070*/
11071
11072Locale.define('fa', 'Date', {
11073
11074	months: ['ژانویه', 'فوریه', 'مارس', 'آپریل', 'مه', 'ژوئن', 'ژوئیه', 'آگوست', 'سپتامبر', 'اکتبر', 'نوامبر', 'دسامبر'],
11075	months_abbr: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'],
11076	days: ['یکشنبه', 'دوشنبه', 'سه شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه', 'شنبه'],
11077	days_abbr: ['ي', 'د', 'س', 'چ', 'پ', 'ج', 'ش'],
11078
11079	// Culture's date order: MM/DD/YYYY
11080	dateOrder: ['month', 'date', 'year'],
11081	shortDate: '%m/%d/%Y',
11082	shortTime: '%I:%M%p',
11083	AM: 'ق.ظ',
11084	PM: 'ب.ظ',
11085
11086	// Date.Extras
11087	ordinal: 'ام',
11088
11089	lessThanMinuteAgo: 'کمتر از یک دقیقه پیش',
11090	minuteAgo: 'حدود یک دقیقه پیش',
11091	minutesAgo: '{delta} دقیقه پیش',
11092	hourAgo: 'حدود یک ساعت پیش',
11093	hoursAgo: 'حدود {delta} ساعت پیش',
11094	dayAgo: '1 روز پیش',
11095	daysAgo: '{delta} روز پیش',
11096	weekAgo: '1 هفته پیش',
11097	weeksAgo: '{delta} هفته پیش',
11098	monthAgo: '1 ماه پیش',
11099	monthsAgo: '{delta} ماه پیش',
11100	yearAgo: '1 سال پیش',
11101	yearsAgo: '{delta} سال پیش',
11102
11103	lessThanMinuteUntil: 'کمتر از یک دقیقه از حالا',
11104	minuteUntil: 'حدود یک دقیقه از حالا',
11105	minutesUntil: '{delta} دقیقه از حالا',
11106	hourUntil: 'حدود یک ساعت از حالا',
11107	hoursUntil: 'حدود {delta} ساعت از حالا',
11108	dayUntil: '1 روز از حالا',
11109	daysUntil: '{delta} روز از حالا',
11110	weekUntil: '1 هفته از حالا',
11111	weeksUntil: '{delta} هفته از حالا',
11112	monthUntil: '1 ماه از حالا',
11113	monthsUntil: '{delta} ماه از حالا',
11114	yearUntil: '1 سال از حالا',
11115	yearsUntil: '{delta} سال از حالا'
11116
11117});
11118
11119
11120/*
11121---
11122
11123name: Locale.fa.Form.Validator
11124
11125description: Form Validator messages for Persian.
11126
11127license: MIT-style license
11128
11129authors:
11130  - Amir Hossein Hodjaty Pour
11131
11132requires:
11133  - /Locale
11134
11135provides: [Locale.fa.Form.Validator]
11136
11137...
11138*/
11139
11140Locale.define('fa', 'FormValidator', {
11141
11142	required: 'این فیلد الزامی است.',
11143	minLength: 'شما باید حداقل {minLength} حرف وارد کنید ({length} حرف وارد کرده اید).',
11144	maxLength: 'لطفا حداکثر {maxLength} حرف وارد کنید (شما {length} حرف وارد کرده اید).',
11145	integer: 'لطفا از عدد صحیح استفاده کنید. اعداد اعشاری (مانند 1.25) مجاز نیستند.',
11146	numeric: 'لطفا فقط داده عددی وارد کنید (مانند "1" یا "1.1" یا "1-" یا "1.1-").',
11147	digits: 'لطفا فقط از اعداد و علامتها در این فیلد استفاده کنید (برای مثال شماره تلفن با خط تیره و نقطه قابل قبول است).',
11148	alpha: 'لطفا فقط از حروف الفباء برای این بخش استفاده کنید. کاراکترهای دیگر و فاصله مجاز نیستند.',
11149	alphanum: 'لطفا فقط از حروف الفباء و اعداد در این بخش استفاده کنید. کاراکترهای دیگر و فاصله مجاز نیستند.',
11150	dateSuchAs: 'لطفا یک تاریخ معتبر مانند {date} وارد کنید.',
11151	dateInFormatMDY: 'لطفا یک تاریخ معتبر به شکل MM/DD/YYYY وارد کنید (مانند "12/31/1999").',
11152	email: 'لطفا یک آدرس ایمیل معتبر وارد کنید. برای مثال "[email protected]".',
11153	url: 'لطفا یک URL معتبر مانند http://www.example.com وارد کنید.',
11154	currencyDollar: 'لطفا یک محدوده معتبر برای این بخش وارد کنید مانند 100.00$ .',
11155	oneRequired: 'لطفا حداقل یکی از فیلدها را پر کنید.',
11156	errorPrefix: 'خطا: ',
11157	warningPrefix: 'هشدار: ',
11158
11159	// Form.Validator.Extras
11160	noSpace: 'استفاده از فاصله در این بخش مجاز نیست.',
11161	reqChkByNode: 'موردی انتخاب نشده است.',
11162	requiredChk: 'این فیلد الزامی است.',
11163	reqChkByName: 'لطفا یک {label} را انتخاب کنید.',
11164	match: 'این فیلد باید با فیلد {matchName} مطابقت داشته باشد.',
11165	startDate: 'تاریخ شروع',
11166	endDate: 'تاریخ پایان',
11167	currendDate: 'تاریخ کنونی',
11168	afterDate: 'تاریخ میبایست برابر یا بعد از {label} باشد',
11169	beforeDate: 'تاریخ میبایست برابر یا قبل از {label} باشد',
11170	startMonth: 'لطفا ماه شروع را انتخاب کنید',
11171	sameMonth: 'این دو تاریخ باید در یک ماه باشند - شما باید یکی یا هر دو را تغییر دهید.',
11172	creditcard: 'شماره کارت اعتباری که وارد کرده اید معتبر نیست. لطفا شماره را بررسی کنید و مجددا تلاش کنید. {length} رقم وارد شده است.'
11173
11174});
11175
11176
11177/*
11178---
11179
11180name: Locale.fi-FI.Date
11181
11182description: Date messages for Finnish.
11183
11184license: MIT-style license
11185
11186authors:
11187  - ksel
11188
11189requires:
11190  - /Locale
11191
11192provides: [Locale.fi-FI.Date]
11193
11194...
11195*/
11196
11197Locale.define('fi-FI', 'Date', {
11198
11199	// NOTE: months and days are not capitalized in finnish
11200	months: ['tammikuu', 'helmikuu', 'maaliskuu', 'huhtikuu', 'toukokuu', 'kesäkuu', 'he
11200inäkuu', 'elokuu', 'syyskuu', 'lokakuu', 'marraskuu', 'joulukuu'],
11201
11202	// these abbreviations are really not much used in finnish because they obviously won't abbreviate very much. ;)
11203	// NOTE: sometimes one can see forms such as "tammi", "helmi", etc. but that is not proper finnish.
11204	months_abbr: ['tammik.', 'helmik.', 'maalisk.', 'huhtik.', 'toukok.', 'kesäk.', 'heinäk.', 'elok.', 'syysk.', 'lokak.', 'marrask.', 'jouluk.'],
11205
11206	days: ['sunnuntai', 'maanantai', 'tiistai', 'keskiviikko', 'torstai', 'perjantai', 'lauantai'],
11207	days_abbr: ['su', 'ma', 'ti', 'ke', 'to', 'pe', 'la'],
11208
11209	// Culture's date order: DD/MM/YYYY
11210	dateOrder: ['date', 'month', 'year'],
11211	shortDate: '%d.%m.%Y',
11212	shortTime: '%H:%M',
11213	AM: 'AM',
11214	PM: 'PM',
11215	firstDayOfWeek: 1,
11216
11217	// Date.Extras
11218	ordinal: '.',
11219
11220	lessThanMinuteAgo: 'vajaa minuutti sitten',
11221	minuteAgo: 'noin minuutti sitten',
11222	minutesAgo: '{delta} minuuttia sitten',
11223	hourAgo: 'noin tunti sitten',
11224	hoursAgo: 'noin {delta} tuntia sitten',
11225	dayAgo: 'päivä sitten',
11226	daysAgo: '{delta} päivää sitten',
11227	weekAgo: 'viikko sitten',
11228	weeksAgo: '{delta} viikkoa sitten',
11229	monthAgo: 'kuukausi sitten',
11230	monthsAgo: '{delta} kuukautta sitten',
11231	yearAgo: 'vuosi sitten',
11232	yearsAgo: '{delta} vuotta sitten',
11233
11234	lessThanMinuteUntil: 'vajaan minuutin kuluttua',
11235	minuteUntil: 'noin minuutin kuluttua',
11236	minutesUntil: '{delta} minuutin kuluttua',
11237	hourUntil: 'noin tunnin kuluttua',
11238	hoursUntil: 'noin {delta} tunnin kuluttua',
11239	dayUntil: 'päivän kuluttua',
11240	daysUntil: '{delta} päivän kuluttua',
11241	weekUntil: 'viikon kuluttua',
11242	weeksUntil: '{delta} viikon kuluttua',
11243	monthUntil: 'kuukauden kuluttua',
11244	monthsUntil: '{delta} kuukauden kuluttua',
11245	yearUntil: 'vuoden kuluttua',
11246	yearsUntil: '{delta} vuoden kuluttua'
11247
11248});
11249
11250
11251/*
11252---
11253
11254name: Locale.fi-FI.Form.Validator
11255
11256description: Form Validator messages for Finnish.
11257
11258license: MIT-style license
11259
11260authors:
11261  - ksel
11262
11263requires:
11264  - /Locale
11265
11266provides: [Locale.fi-FI.Form.Validator]
11267
11268...
11269*/
11270
11271Locale.define('fi-FI', 'FormValidator', {
11272
11273	required: 'Tämä kenttä on pakollinen.',
11274	minLength: 'Ole hyvä ja anna vähintään {minLength} merkkiä (annoit {length} merkkiä).',
11275	maxLength: 'Älä anna enempää kuin {maxLength} merkkiä (annoit {length} merkkiä).',
11276	integer: 'Ole hyvä ja anna kokonaisluku. Luvut, joissa on desimaaleja (esim. 1.25) eivät ole sallittuja.',
11277	numeric: 'Anna tähän kenttään lukuarvo (kuten "1" tai "1.1" tai "-1" tai "-1.1").',
11278	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).',
11279	alpha: 'Anna tähän kenttään vain kirjaimia (a-z). Välilyönnit tai muut merkit eivät ole sallittuja.',
11280	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.',
11281	dateSuchAs: 'Ole hyvä ja anna kelvollinen päivmäärä, kuten esimerkiksi {date}',
11282	dateInFormatMDY: 'Ole hyvä ja anna kelvollinen päivämäärä muodossa pp/kk/vvvv (kuten "12/31/1999")',
11283	email: 'Ole hyvä ja anna kelvollinen sähköpostiosoite (kuten esimerkiksi "[email protected]").',
11284	url: 'Ole hyvä ja anna kelvollinen URL, kuten esimerkiksi http://www.example.com.',
11285	currencyDollar: 'Ole hyvä ja anna kelvollinen eurosumma (kuten esimerkiksi 100,00 EUR) .',
11286	oneRequired: 'Ole hyvä ja syötä jotakin ainakin johonkin näistä kentistä.',
11287	errorPrefix: 'Virhe: ',
11288	warningPrefix: 'Varoitus: ',
11289
11290	// Form.Validator.Extras
11291	noSpace: 'Tässä syötteessä ei voi olla välilyöntejä',
11292	reqChkByNode: 'Ei valintoja.',
11293	requiredChk: 'Tämä kenttä on pakollinen.',
11294	reqChkByName: 'Ole hyvä ja valitse {label}.',
11295	match: 'Tämän kentän tulee vastata kenttää {matchName}',
11296	startDate: 'alkupäivämäärä',
11297	endDate: 'loppupäivämäärä',
11298	currendDate: 'nykyinen päivämäärä',
11299	afterDate: 'Päivämäärän tulisi olla sama tai myöhäisempi ajankohta kuin {label}.',
11300	beforeDate: 'Päivämäärän tulisi olla sama tai aikaisempi ajankohta kuin {label}.',
11301	startMonth: 'Ole hyvä ja valitse aloituskuukausi',
11302	sameMonth: 'Näiden kahden päivämäärän tulee olla saman kuun sisällä -- sinun pitää muuttaa jompaa kumpaa.',
11303	creditcard: 'Annettu luottokortin numero ei kelpaa. Ole hyvä ja tarkista numero sekä yritä uudelleen. {length} numeroa syötetty.'
11304
11305});
11306
11307
11308/*
11309---
11310
11311name: Locale.fi-FI.Number
11312
11313description: Finnish number messages
11314
11315license: MIT-style license
11316
11317authors:
11318  - ksel
11319
11320requires:
11321  - /Locale
11322  - /Locale.EU.Number
11323
11324provides: [Locale.fi-FI.Number]
11325
11326...
11327*/
11328
11329Locale.define('fi-FI', 'Number', {
11330
11331	group: ' ' // grouped by space
11332
11333}).inherit('EU', 'Number');
11334
11335
11336/*
11337---
11338
11339name: Locale.fr-FR.Date
11340
11341description: Date messages for French.
11342
11343license: MIT-style license
11344
11345authors:
11346  - Nicolas Sorosac
11347  - Antoine Abt
11348
11349requires:
11350  - /Locale
11351
11352provides: [Locale.fr-FR.Date]
11353
11354...
11355*/
11356
11357Locale.define('fr-FR', 'Date', {
11358
11359	months: ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'],
11360	months_abbr: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'],
11361	days: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'],
11362	days_abbr: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],
11363
11364	// Culture's date order: DD/MM/YYYY
11365	dateOrder: ['date', 'month', 'year'],
11366	shortDate: '%d/%m/%Y',
11367	shortTime: '%H:%M',
11368	AM: 'AM',
11369	PM: 'PM',
11370	firstDayOfWeek: 1,
11371
11372	// Date.Extras
11373	ordinal: function(dayOfMonth){
11374		return (dayOfMonth > 1) ? '' : 'er';
11375	},
11376
11377	lessThanMinuteAgo: "il y a moins d'une minute",
11378	minuteAgo: 'il y a une minute',
11379	minutesAgo: 'il y a {delta} minutes',
11380	hourAgo: 'il y a une heure',
11381	hoursAgo: 'il y a {delta} heures',
11382	dayAgo: 'il y a un jour',
11383	daysAgo: 'il y a {delta} jours',
11384	weekAgo: 'il y a une semaine',
11385	weeksAgo: 'il y a {delta} semaines',
11386	monthAgo: 'il y a 1 mois',
11387	monthsAgo: 'il y a {delta} mois',
11388	yearthAgo: 'il y a 1 an',
11389	yearsAgo: 'il y a {delta} ans',
11390
11391	lessThanMinuteUntil: "dans moins d'une minute",
11392	minuteUntil: 'dans une minute',
11393	minutesUntil: 'dans {delta} minutes',
11394	hourUntil: 'dans une heure',
11395	hoursUntil: 'dans {delta} heures',
11396	dayUntil: 'dans un jour',
11397	daysUntil: 'dans {delta} jours',
11398	weekUntil: 'dans 1 semaine',
11399	weeksUntil: 'dans {delta} semaines',
11400	monthUntil: 'dans 1 mois',
11401	monthsUntil: 'dans {delta} mois',
11402	yearUntil: 'dans 1 an',
11403	yearsUntil: 'dans {delta} ans'
11404
11405});
11406
11407
11408/*
11409---
11410
11411name: Locale.fr-FR.Form.Validator
11412
11413description: Form Validator messages for French.
11414
11415license: MIT-style license
11416
11417authors:
11418  - Miquel Hudin
11419  - Nicolas Sorosac
11420
11421requires:
11422  - /Locale
11423
11424provides: [Locale.fr-FR.Form.Validator]
11425
11426...
11427*/
11428
11429Locale.define('fr-FR', 'FormValidator', {
11430
11431	required: 'Ce champ est obligatoire.',
11432	length: 'Veuillez saisir {length} caract&egrave;re(s) (vous avez saisi {elLength} caract&egrave;re(s)',
11433	minLength: 'Veuillez saisir un minimum de {minLength} caract&egrave;re(s) (vous avez saisi {length} caract&egrave;re(s)).',
11434	maxLength: 'Veuillez saisir un maximum de {maxLength} caract&egrave;re(s) (vous avez saisi {length} caract&egrave;re(s)).',
11435	integer: 'Veuillez saisir un nombre entier dans ce champ. Les nombres d&eacute;cimaux (ex : "1,25") ne sont pas autoris&eacute;s.',
11436	numeric: 'Veuillez saisir uniquement des chiffres dans ce champ (ex : "1" ou "1,1" ou "-1" ou "-1,1").',
11437	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;).",
11438	alpha: 'Veuillez saisir uniquement des lettres (a-z) dans ce champ. Les espaces ou autres caract&egrave;res ne sont pas autoris&eacute;s.',
11439	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.',
11440	dateSuchAs: 'Veuillez saisir une date correcte comme {date}',
11441	dateInFormatMDY: 'Veuillez saisir une date correcte, au format JJ/MM/AAAA (ex : "31/11/1999").',
11442	email: 'Veuillez saisir une adresse de courrier &eacute;lectronique. Par example "[email protected]".',
11443	url: 'Veuillez saisir une URL, comme http://www.example.com.',
11444	currencyDollar: 'Veuillez saisir une quantit&eacute; correcte. Par example 100,00&euro;.',
11445	oneRequired: 'Veuillez s&eacute;lectionner au moins une de ces options.',
11446	errorPrefix: 'Erreur : ',
11447	warningPrefix: 'Attention : ',
11448
11449	// Form.Validator.Extras
11450	noSpace: "Ce champ n'accepte pas les espaces.",
11451	reqChkByNode: "Aucun &eacute;l&eacute;ment n'est s&eacute;lectionn&eacute;.",
11452	requiredChk: 'Ce champ est obligatoire.',
11453	reqChkByName: 'Veuillez s&eacute;lectionner un(e) {label}.',
11454	match: 'Ce champ doit correspondre avec le champ {matchName}.',
11455	startDate: 'date de d&eacute;but',
11456	endDate: 'date de fin',
11457	currendDate: 'date actuelle',
11458	afterDate: 'La date doit &ecirc;tre identique ou post&eacute;rieure &agrave; {label}.',
11459	beforeDate: 'La date doit &ecirc;tre identique ou ant&eacute;rieure &agrave; {label}.',
11460	startMonth: 'Veuillez s&eacute;lectionner un mois de d&eacute;but.',
11461	sameMonth: 'Ces deux dates doivent &ecirc;tre dans le m&ecirc;me mois - vous devez en modifier une.',
11462	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).'
11463
11464}
11464);
11465
11466
11467/*
11468---
11469
11470name: Locale.fr-FR.Number
11471
11472description: Number messages for French.
11473
11474license: MIT-style license
11475
11476authors:
11477  - Arian Stolwijk
11478  - sv1l
11479
11480requires:
11481  - /Locale
11482  - /Locale.EU.Number
11483
11484provides: [Locale.fr-FR.Number]
11485
11486...
11487*/
11488
11489Locale.define('fr-FR', 'Number', {
11490
11491	group: ' ' // In fr-FR localization, group character is a blank space
11492
11493}).inherit('EU', 'Number');
11494
11495
11496/*
11497---
11498
11499name: Locale.he-IL.Date
11500
11501description: Date messages for Hebrew.
11502
11503license: MIT-style license
11504
11505authors:
11506  - Elad Ossadon
11507
11508requires:
11509  - /Locale
11510
11511provides: [Locale.he-IL.Date]
11512
11513...
11514*/
11515
11516Locale.define('he-IL', 'Date', {
11517
11518	months: ['ינואר', 'פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר', 'דצמבר'],
11519	months_abbr: ['ינואר', 'פברואר', 'מרץ', 'אפריל', 'מאי', 'יוני', 'יולי', 'אוגוסט', 'ספטמבר', 'אוקטובר', 'נובמבר', 'דצמבר'],
11520	days: ['ראשון', 'שני', 'שלישי', 'רביעי', 'חמישי', 'שישי', 'שבת'],
11521	days_abbr: ['ראשון', 'שני', 'שלישי', 'רביעי', 'חמישי', 'שישי', 'שבת'],
11522
11523	// Culture's date order: MM/DD/YYYY
11524	dateOrder: ['date', 'month', 'year'],
11525	shortDate: '%d/%m/%Y',
11526	shortTime: '%H:%M',
11527	AM: 'AM',
11528	PM: 'PM',
11529	firstDayOfWeek: 0,
11530
11531	// Date.Extras
11532	ordinal: '',
11533
11534	lessThanMinuteAgo: 'לפני פחות מדקה',
11535	minuteAgo: 'לפני כדקה',
11536	minutesAgo: 'לפני {delta} דקות',
11537	hourAgo: 'לפני כשעה',
11538	hoursAgo: 'לפני {delta} שעות',
11539	dayAgo: 'לפני יום',
11540	daysAgo: 'לפני {delta} ימים',
11541	weekAgo: 'לפני שבוע',
11542	weeksAgo: 'לפני {delta} שבועות',
11543	monthAgo: 'לפני חודש',
11544	monthsAgo: 'לפני {delta} חודשים',
11545	yearAgo: 'לפני שנה',
11546	yearsAgo: 'לפני {delta} שנים',
11547
11548	lessThanMinuteUntil: 'בעוד פחות מדקה',
11549	minuteUntil: 'בעוד כדקה',
11550	minutesUntil: 'בעוד {delta} דקות',
11551	hourUntil: 'בעוד כשעה',
11552	hoursUntil: 'בעוד {delta} שעות',
11553	dayUntil: 'בעוד יום',
11554	daysUntil: 'בעוד {delta} ימים',
11555	weekUntil: 'בעוד שבוע',
11556	weeksUntil: 'בעוד {delta} שבועות',
11557	monthUntil: 'בעוד חודש',
11558	monthsUntil: 'בעוד {delta} חודשים',
11559	yearUntil: 'בעוד שנה',
11560	yearsUntil: 'בעוד {delta} שנים'
11561
11562});
11563
11564
11565/*
11566---
11567
11568name: Locale.he-IL.Form.Validator
11569
11570description: Form Validator messages for Hebrew.
11571
11572license: MIT-style license
11573
11574authors:
11575  - Elad Ossadon
11576
11577requires:
11578  - /Locale
11579
11580provides: [Locale.he-IL.Form.Validator]
11581
11582...
11583*/
11584
11585Locale.define('he-IL', 'FormValidator', {
11586
11587	required: 'נא למלא שדה זה.',
11588	minLength: 'נא להזין לפחות {minLength} תווים (הזנת {length} תווים).',
11589	maxLength: 'נא להזין עד {maxLength} תווים (הזנת {length} תווים).',
11590	integer: 'נא להזין מספר שלם לשדה זה. מספרים עשרוניים (כמו 1.25) אינם חוקיים.',
11591	numeric: 'נא להזין ערך מספרי בלבד בשדה זה (כמו "1", "1.1", "-1" או "-1.1").',
11592	digits: 'נא להזין רק ספרות וסימני הפרדה בשדה זה (למשל, מספר טלפון עם מקפים או נקודות הוא חוקי).',
11593	alpha: 'נא להזין רק אותיות באנגלית (a-z) בשדה זה. רווחים או תווים אחרים אינם חוקיים.',
11594	alphanum: 'נא להזין רק אותריות באנגלית (a-z) או ספרות (0-9) בשדה זה. אווחרים או תווים אחרים אינם חוקיים.',
11595	dateSuchAs: 'נא להזין תאריך חוקי, כמו {date}',
11596	dateInFormatMDY: 'נא להזין תאריך חוקי בפורמט MM/DD/YYYY (כמו "12/31/1999")',
11597	email: 'נא להזין כתובת אימייל חוקית. לדוגמה: "[email protected]".',
11598	url: 'נא להזין כתובת אתר חוקית, כמו http://www.example.com.',
11599	currencyDollar: 'נא להזין סכום דולרי חוקי. לדוגמה $100.00.',
11600	oneRequired: 'נא לבחור לפחות בשדה אחד.',
11601	errorPrefix: 'שגיאה: ',
11602	warningPrefix: 'אזהרה: ',
11603
11604	// Form.Validator.Extras
11605	noSpace: 'אין להזין רווחים בשדה זה.',
11606	reqChkByNode: 'נא לבחור אחת מהאפשרויות.',
11607	requiredChk: 'שדה זה נדרש.',
11608	reqChkByName: 'נא לבחור {label}.',
11609	match: 'שדה זה צריך להתאים לשדה {matchName}',
11610	startDate: 'תאריך ההתחלה',
11611	endDate: 'תאריך הסיום',
11612	currendDate: 'התאריך הנוכחי',
11613	afterDate: 'התאריך צריך להיות זהה או אחרי {label}.',
11614	beforeDate: 'התאריך צריך להיות זהה או לפני {label}.',
11615	startMonth: 'נא לבחור חודש התחלה',
11616	sameMonth: 'שני תאריכים אלה צריכים להיות באותו חודש - נא לשנות אחד התאריכים.',
11617	creditcard: 'מספר כרטיס האשראי שהוזן אינו חוקי. נא לבדוק שנית. הוזנו {length} ספרות.'
11618
11619});
11620
11621
11622/*
11623---
11624
11625name: Locale.he-IL.Number
11626
11627description: Number messages for Hebrew.
11628
11629license: MIT-style license
11630
11631authors:
11632  - Elad Ossadon
11633
11634requires:
11635  - /Locale
11636
11637provides: [Locale.he-IL.Number]
11638
11639...
11640*/
11641
11642Locale.define('he-IL', 'Number', {
11643
11644	decimal: '.',
11645	group: ',',
11646
11647	currency: {
11648		suffix: ' ₪'
11649	}
11650
11651});
11652
11653
11654/*
11655---
11656
11657name: Locale.hu-HU.Date
11658
11659description: Date messages for Hungarian.
11660
11661license: MIT-style license
11662
11663authors:
11664  - Zsolt Szegheő
11665
11666requires:
11667  - /Locale
11668
11669provides: [Locale.hu-HU.Date]
11670
11671...
11672*/
11673
11674Locale.define('hu-HU', 'Date', {
11675
11676	months: ['Január', 'Február', 'Március', 'Április', 'Május', 'Június', 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'],
11677	months_abbr: ['jan.', 'febr.', 'márc.', 'ápr.', 'máj.', 'jún.', 'júl.', 'aug.', 'szept.', 'okt.', 'nov.', 'dec.'],
11678	days: ['Vasárnap', 'Hétfő', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat'],
11679	days_abbr: ['V', 'H', 'K', 'Sze', 'Cs', 'P', 'Szo'],
11680
11681	// Culture's date order: YYYY.MM.DD.
11682	dateOrder: ['year', 'month', 'date'],
11683	shortDate: '%Y.%m.%d.',
11684	shortTime: '%I:%M',
11685	AM: 'de.',
11686	PM: 'du.',
11687	firstDayOfWeek: 1,
11688
11689	// Date.Extras
11690	ordinal: '.',
11691
11692	lessThanMinuteAgo: 'alig egy perce',
11693	minuteAgo: 'egy perce',
11694	minutesAgo: '{delta} perce',
11695	hourAgo: 'egy órája',
11696	hoursAgo: '{delta} órája',
11697	dayAgo: '1 napja',
11698	daysAgo: '{delta} napja',
11699	weekAgo: '1 hete',
11700	weeksAgo: '{delta} hete',
11701	monthAgo: '1 hónapja',
11702	monthsAgo: '{delta} hónapja',
11703	yearAgo: '1 éve',
11704	yearsAgo: '{delta} éve',
11705
11706	lessThanMinuteUntil: 'alig egy perc múlva',
11707	minuteUntil: 'egy perc múlva',
11708	minutesUntil: '{delta} perc múlva',
11709	hourUntil: 'egy óra múlva',
11710	hoursUntil: '{delta} óra múlva',
11711	dayUntil: '1 nap múlva',
11712	daysUntil: '{delta} nap múlva',
11713	weekUntil: '1 hét múlva',
11714	weeksUntil: '{delta} hét múlva',
11715	monthUntil: '1 hónap múlva',
11716	monthsUntil: '{delta} hónap múlva',
11717	yearUntil: '1 év múlva',
11718	yearsUntil: '{delta} év múlva'
11719
11720});
11721
11722
11723/*
11724---
11725
11726name: Locale.hu-HU.Form.Validator
11727
11728description: Form Validator messages for Hungarian.
11729
11730license: MIT-style license
11731
11732authors:
11733  - Zsolt Szegheő
11734
11735requires:
11736  - /Locale
11737
11738provides: [Locale.hu-HU.Form.Validator]
11739
11740...
11741*/
11742
11743Locale.define('hu-HU', 'FormValidator', {
11744
11745	required: 'A mező kitöltése kötelező.',
11746	minLength: 'Legalább {minLength} karakter megadása szükséges (megadva {length} karakter).',
11747	maxLength: 'Legfeljebb {maxLength} karakter megadása lehetséges (megadva {length} karakter).',
11748	integer: 'Egész szám megadása szükséges. A tizedesjegyek (pl. 1.25) nem engedélyezettek.',
11749	numeric: 'Szám megadása szükséges (pl. "1" vagy "1.1" vagy "-1" vagy "-1.1").',
11750	digits: 'Csak számok és írásjelek megadása lehetséges (pl. telefonszám kötőjelek és/vagy perjelekkel).',
11751	alpha: 'Csak betűk (a-z) megadása lehetséges. Szóköz és egyéb karakterek nem engedélyezettek.',
11752	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.',
11753	dateSuchAs: 'Valós dátum megadása szükséges (pl. {date}).',
11754	dateInFormatMDY: 'Valós dátum megadása szükséges ÉÉÉÉ.HH.NN. formában. (pl. "1999.12.31.")',
11755	email: 'Valós e-mail cím megadása szükséges (pl. "[email protected]").',
11756	url: 'Valós URL megadása szükséges (pl. http://www.example.com).',
11757	currencyDollar: 'Valós pénzösszeg megadása szükséges (pl. 100.00 Ft.).',
11758	oneRequired: 'Az alábbi mezők legalább egyikének kitöltése kötelező.',
11759	errorPrefix: 'Hiba: ',
11760	warningPrefix: 'Figyelem: ',
11761
11762	// Form.Validator.Extras
11763	noSpace: 'A mező nem tartalmazhat szóközöket.',
11764	reqChkByNode: 'Nincs egyetlen kijelölt elem sem.',
11765	requiredChk: 'A mező kitöltése kötelező.',
11766	reqChkByName: 'Egy {label} kiválasztása szükséges.',
11767	match: 'A mezőnek egyeznie kell a(z) {matchName} mezővel.',
11768	startDate: 'a kezdet dátuma',
11769	endDate: 'a vég dátuma',
11770	currendDate: 'jelenlegi dátum',
11771	afterDate: 'A dátum nem lehet kisebb, mint {label}.',
11772	beforeDate: 'A dátum nem lehet nagyobb, mint {label}.',
11773	startMonth: 'Kezdeti hónap megadása szükséges.',
11774	sameMonth: 'A két dátumnak ugyanazon hónapban kell lennie.',
11775	creditcard: 'A megadott bankkártyaszám nem valódi (megadva {length} számjegy).'
11776
11777});
11778
11779
11780/*
11781---
11782
11783name: Locale.it-IT.Date
11784
11785description: Date messages for Italian.
11786
11787license: MIT-style license.
11788
11789authors:
11790  - Andrea Novero
11791  - Valerio Proietti
11792
11793requires:
11794  - /Locale
11795
11796provides: [Locale.it-IT.Date]
11797
11798...
11799*/
11800
11801Locale.define('it-IT', 'Date', {
11802
11803	months: ['Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre'],
11804	months_abbr: ['gen', 'feb', 'mar', 'apr', 'mag', 'giu', 'lug', 'ago', 'set', 'ott', 'nov', 'dic'],
11805	days: ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'],
11806	days_abbr: ['dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab'],
11807
11808	// Culture's date order: DD/MM/YYYY
11809	dateOrder: ['date', 'month', 'year'],
11810	shortDate: '%d/%m/%Y',
11811	shortTime: '%H.%M',
11812	AM: 'AM',
11813	PM: 'PM',
11814	firstDayOfWeek: 1,
11815
11816	// Date.Extras
11817	ordinal: 'º',
11818
11819	lessThanMinuteAgo: 'meno di un minuto fa',
11820	minuteAgo: 'circa un minuto fa',
11821	minutesAgo: 'circa {delta} minuti fa',
11822	hourAgo: "circa un'ora fa",
11823	hoursAgo: 'circa {delta} ore fa',
11824	dayAgo: 'circa 1 giorno fa',
11825	daysAgo: 'circa {delta} giorni fa',
11826	weekAgo: 'una settimana fa',
11827	weeksAgo: '{delta} settimane fa',
11828	monthAgo: 'un mese fa',
11829	monthsAgo: '{delta} mesi fa',
11830	yearAgo: 'un anno fa',
11831	yearsAgo: '{delta} anni fa',
11832
11833	lessThanMinuteUntil: 'tra meno di un minuto',
11834	minuteUntil: 'tra circa un minuto',
11835	minutesUntil: 'tra circa {delta} minuti',
11836	hourUntil: "tra circa un'ora",
11837	hoursUntil: 'tra circa {delta} ore',
11838	dayUntil: 'tra circa un giorno',
11839	daysUntil: 'tra circa {delta} giorni',
11840	weekUntil: 'tra una settimana',
11841	weeksUntil: 'tra {delta} settimane',
11842	monthUntil: 'tra un mese',
11843	monthsUntil: 'tra {delta} mesi',
11844	yearUntil: 'tra un anno',
11845	yearsUntil: 'tra {delta} anni'
11846
11847});
11848
11849
11850/*
11851---
11852
11853name: Locale.it-IT.Form.Validator
11854
11855description: Form Validator messages for Italian.
11856
11857license: MIT-style license
11858
11859authors:
11860  - Leonardo Laureti
11861  - Andrea Novero
11862
11863requires:
11864  - /Locale
11865
11866provides: [Locale.it-IT.Form.Validator]
11867
11868...
11869*/
11870
11871Locale.define('it-IT', 'FormValidator', {
11872
11873	required: 'Il campo &egrave; obbligatorio.',
11874	minLength: 'Inserire almeno {minLength} caratteri (ne sono stati inseriti {length}).',
11875	maxLength: 'Inserire al massimo {maxLength} caratteri (ne sono stati inseriti {length}).',
11876	integer: 'Inserire un numero intero. Non sono consentiti decimali (es.: 1.25).',
11877	numeric: 'Inserire solo valori numerici (es.: "1" oppure "1.1" oppure "-1" oppure "-1.1").',
11878	digits: 'Inserire solo numeri e caratteri di punteggiatura. Per esempio &egrave; consentito un numero telefonico con trattini o punti.',
11879	alpha: 'Inserire solo lettere (a-z). Non sono consentiti spazi o altri caratteri.',
11880	alphanum: 'Inserire solo lettere (a-z) o numeri (0-9). Non sono consentiti spazi o altri caratteri.',
11881	dateSuchAs: 'Inserire una data valida del tipo {date}',
11882	dateInFormatMDY: 'Inserire una data valida nel formato MM/GG/AAAA (es.: "12/31/1999")',
11883	email: 'Inserire un indirizzo email valido. Per esempio "[email protected]".',
11884	url: 'Inserire un indirizzo valido. Per esempio "http://www.example.com".',
11885	currencyDollar: 'Inserire un importo valido. Per esempio "$100.00".',
11886	oneRequired: 'Completare almeno uno dei campi richiesti.',
11887	errorPrefix: 'Errore: ',
11888	warningPrefix: 'Attenzione: ',
11889
11890	// Form.Validator.Extras
11891	noSpace: 'Non sono consentiti spazi.',
11892	reqChkByNode: 'Nessuna voce selezionata.',
11893	requiredChk: 'Il campo &egrave; obbligatorio.',
11894	reqChkByName: 'Selezionare un(a) {label}.',
11895	match: 'Il valore deve corrispondere al campo {matchName}',
11896	startDate: "data d'inizio",
11897	endDate: 'data di fine',
11898	currendDate: 'data attuale',
11899	afterDate: 'La data deve corrispondere o essere successiva al {label}.',
11900	beforeDate: 'La data deve corrispondere o essere precedente al {label}.',
11901	startMonth: "Selezionare un mese d'inizio",
11902	sameMonth: 'Le due date devono essere dello stesso mese - occorre modificarne una.'
11903
11904});
11905
11906
11907/*
11908---
11909
11910name: Locale.ja-JP.Date
11911
11912description: Date messages for Japanese.
11913
11914license: MIT-style license
11915
11916authors:
11917  - Noritaka Horio
11918
11919requires:
11920  - /Locale
11921
11922provides: [Locale.ja-JP.Date]
11923
11924...
11925*/
11926
11927Locale.define('ja-JP', 'Date', {
11928
11929	months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
11930	months_abbr: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
11931	days: ['日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日'],
11932	days_abbr: ['日', '月', '火', '水', '木', '金', '土'],
11933
11934	// Culture's date order: YYYY/MM/DD
11935	dateOrder: ['year', 'month', 'date'],
11936	shortDate: '%Y/%m/%d',
11937	shortTime: '%H:%M',
11938	AM: '午前',
11939	PM: '午後',
11940	firstDayOfWeek: 0,
11941
11942	// Date.Extras
11943	ordinal: '',
11944
11945	lessThanMinuteAgo: '1分以内前',
11946	minuteAgo: '約1分前',
11947	minutesAgo: '約{delta}分前',
11948	hourAgo: '約1時間前',
11949	hoursAgo: '約{delta}時間前',
11950	dayAgo: '1日前',
11951	daysAgo: '{delta}日前',
11952	weekAgo: '1週間前',
11953	weeksAgo: '{delta}週間前',
11954	monthAgo: '1ヶ月前',
11955	monthsAgo: '{delta}ヶ月前',
11956	yearAgo: '1年前',
11957	yearsAgo: '{delta}年前',
11958
11959	lessThanMinuteUntil: '今から約1分以内',
11960	minuteUntil: '今から約1分',
11961	minutesUntil: '今から約{delta}分',
11962	hourUntil: '今から約1時間',
11963	hoursUntil: '今から約{delta}時間',
11964	dayUntil: '今から1日間',
11965	daysUntil: '今から{delta}日間',
11966	weekUntil: '今から1週間',
11967	weeksUntil: '今から{delta}週間',
11968	monthUntil: '今から1ヶ月',
11969	monthsUntil: '今から{delta}ヶ月',
11970	yearUntil: '今から1年',
11971	yearsUntil: '今から{delta}年'
11972
11973});
11974
11975
11976/*
11977---
11978
11979name: Locale.ja-JP.Form.Validator
11980
11981description: Form Validator messages for Japanese.
11982
11983license: MIT-style license
11984
11985authors:
11986  - Noritaka Horio
11987
11988requires:
11989  - /Locale
11990
11991provides: [Locale.ja-JP.Form.Validator]
11992
11993...
11994*/
11995
11996Locale.define("ja-JP", "FormValidator", {
11997
11998	required: '入力は必須です。',
11999	minLength: '入力文字数は{minLength}以上にしてください。({length}文字)',
12000	maxLength: '入力文字数は{maxLength}以下にしてください。({length}文字)',
12001	integer: '整数を入力してください。',
12002	numeric: '入力できるのは数値だけです。(例: "1", "1.1", "-1", "-1.1"....)',
12003	digits: '入力できるのは数値と句読記号です。 (例: -や+を含む電話番号など).',
12004	alpha: '入力できるのは半角英字だけです。それ以外の文字は入力できません。',
12005	alphanum: '入力できるのは半角英数字だけです。それ以外の文字は入力できません。',
12006	dateSuchAs: '有効な日付を入力してください。{date}',
12007	dateInFormatMDY: '日付の書式に誤りがあります。YYYY/MM/DD (i.e. "1999/12/31")',
12008	email: 'メールアドレスに誤りがあります。',
12009	url: 'URLアドレスに誤りがあります。',
12010	currencyDollar: '金額に誤りがあります。',
12011	oneRequired: 'ひとつ以上入力してください。',
12012	errorPrefix: 'エラー: ',
12013	warningPrefix: '警告: ',
12014
12015	// FormValidator.Extras
12016	noSpace: 'スペースは入力できません。',
12017	reqChkByNode: '選択されていません。',
12018	requiredChk: 'この項目は必須です。',
12019	reqChkByName: '{label}を選択してください。',
12020	match: '{matchName}が入力されている場合必須です。',
12021	startDate: '開始日',
12022	endDate: '終了日',
12023	currendDate: '今日',
12024	afterDate: '{label}以降の日付にしてください。',
12025	beforeDate: '{label}以前の日付にしてください。',
12026	startMonth: '開始月を選択してください。',
12027	sameMonth: '日付が同一です。どちらかを変更してください。'
12028
12029});
12030
12031
12032/*
12033---
12034
12035name: Locale.ja-JP.Number
12036
12037description: Number messages for Japanese.
12038
12039license: MIT-style license
12040
12041authors:
12042  - Noritaka Horio
12043
12044requires:
12045  - /Locale
12046
12047provides: [Locale.ja-JP.Number]
12048
12049...
12050*/
12051
12052Locale.define('ja-JP', 'Number', {
12053
12054	decimal: '.',
12055	group: ',',
12056
12057	currency: {
12058		decimals: 0,
12059		prefix: '\\'
12060	}
12061
12062});
12063
12064
12065/*
12066---
12067
12068name: Locale.nl-NL.Date
12069
12070description: Date messages for Dutch.
12071
12072license: MIT-style license
12073
12074authors:
12075  - Lennart Pilon
12076  - Tim Wienk
12077
12078requires:
12079  - /Locale
12080
12081provides: [Locale.nl-NL.Date]
12082
12083...
12084*/
12085
12086Locale.define('nl-NL', 'Date', {
12087
12088	months: ['januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december'],
12089	months_abbr: ['jan', 'feb', 'mrt', 'apr', 'mei', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'],
12090	days: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'],
12091	days_abbr: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'],
12092
12093	// Culture's date order: DD-MM-YYYY
12094	dateOrder: ['date', 'month', 'year'],
12095	shortDate: '%d-%m-%Y',
12096	shortTime: '%H:%M',
12097	AM: 'AM',
12098	PM: 'PM',
12099	firstDayOfWeek: 1,
12100
12101	// Date.Extras
12102	ordinal: 'e',
12103
12104	lessThanMinuteAgo: 'minder dan een minuut geleden',
12105	minuteAgo: 'ongeveer een minuut geleden',
12106	minutesAgo: '{delta} minuten geleden',
12107	hourAgo: 'ongeveer een uur geleden',
12108	hoursAgo: 'ongeveer {delta} uur geleden',
12109	dayAgo: 'een dag geleden',
12110	daysAgo: '{delta} dagen geleden',
12111	weekAgo: 'een week geleden',
12112	weeksAgo: '{delta} weken geleden',
12113	monthAgo: 'een maand geleden',
12114	monthsAgo: '{delta} maanden geleden',
12115	yearAgo: 'een jaar geleden',
12116	yearsAgo: '{delta} jaar geleden',
12117
12118	lessThanMinuteUntil: 'over minder dan een minuut',
12119	minuteUntil: 'over ongeveer een minuut',
12120	minutesUntil: 'over {delta} minuten',
12121	hourUntil: 'over ongeveer een uur',
12122	hoursUntil: 'over {delta} uur',
12123	dayUntil: 'over ongeveer een dag',
12124	daysUntil: 'over {delta} dagen',
12125	weekUntil: 'over een week',
12126	weeksUntil: 'over {delta} weken',
12127	monthUntil: 'over een maand',
12128	monthsUntil: 'over {delta} maanden',
12129	yearUntil: 'over een jaar',
12130	yearsUntil: 'over {delta} jaar'
12131
12132});
12133
12134
12135/*
12136---
12137
12138name: Locale.nl-NL.Form.Validator
12139
12140description: Form Validator messages for Dutch.
12141
12142license: MIT-style license
12143
12144authors:
12145  - Lennart Pilon
12146  - Arian Stolwijk
12147  - Tim Wienk
12148
12149requires:
12150  - /Locale
12151
12152provides: [Locale.nl-NL.Form.Validator]
12153
12154...
12155*/
12156
12157Locale.define('nl-NL', 'FormValidator', {
12158
12159	required: 'Dit veld is verplicht.',
12160	length: 'Vul precies {length} karakters in (je hebt {elLength} karakters ingevoerd).',
12161	minLength: 'Vul minimaal {minLength} karakters in (je hebt {length} karakters ingevoerd).',
12162	maxLength: 'Vul niet meer dan {maxLength} karakters in (je hebt {length} karakters ingevoerd).',
12163	integer: 'Vul een getal in. Getallen met decimalen (bijvoorbeeld 1.25) zijn niet toegestaan.',
12164	numeric: 'Vul alleen numerieke waarden in (bijvoorbeeld "1" of "1.1" of "-1" of "-1.1").',
12165	digits: 'Vul alleen nummers en leestekens in (bijvoorbeeld een telefoonnummer met streepjes is toegestaan).',
12166	alpha: 'Vul alleen letters in (a-z). Spaties en andere karakters zijn niet toegestaan.',
12167	alphanum: 'Vul alleen letters (a-z) of nummers (0-9) in. Spaties en andere karakters zijn niet toegestaan.',
12168	dateSuchAs: 'Vul een geldige datum in, zoals {date}',
12169	dateInFormatMDY: 'Vul een geldige datum, in het formaat MM/DD/YYYY (bijvoorbeeld "12/31/1999")',
12170	email: 'Vul een geldig e-mailadres in. Bijvoorbeeld "[email protected]".',
12171	url: 'Vul een geldige URL in, zoals http://www.example.com.',
12172	currencyDollar: 'Vul een geldig $ bedrag in. Bijvoorbeeld $100.00 .',
12173	oneRequired: 'Vul iets in bij in ieder geval een van deze velden.',
12174	warningPrefix: 'Waarschuwing: ',
12175	errorPrefix: 'Fout: ',
12176
12177	// Form.Validator.Extras
12178	noSpace: 'Spaties zijn niet toegestaan in dit veld.',
12179	reqChkByNode: 'Er zijn geen items geselecteerd.',
12180	requiredChk: 'Dit veld is verplicht.',
12181	reqChkByName: 'Selecteer een {label}.',
12182	match: 'Dit veld moet overeen komen met het {matchName} veld',
12183	startDate: 'de begin datum',
12184	endDate: 'de eind datum',
12185	currendDate: 'de huidige datum',
12186	afterDate: 'De datum moet hetzelfde of na {label} zijn.',
12187	beforeDate: 'De datum moet hetzelfde of voor {label} zijn.',
12188	startMonth: 'Selecteer een begin maand',
12189	sameMonth: 'Deze twee data moeten in dezelfde maand zijn - u moet een van beide aanpassen.',
12190	creditcard: 'Het ingevulde creditcardnummer is niet geldig. Controleer het nummer en probeer opnieuw. {length} getallen ingevuld.'
12191
12192});
12193
12194
12195/*
12196---
12197
12198name: Locale.nl-NL.Number
12199
12200description: Number messages for Dutch.
12201
12202license: MIT-style license
12203
12204authors:
12205  - Arian Stolwijk
12206
12207requires:
12208  - /Locale
12209  - /Locale.EU.Number
12210
12211provides: [Locale.nl-NL.Number]
12212
12213...
12214*/
12215
12216Locale.define('nl-NL').inherit('EU', 'Number');
12217
12218
12219
12220
12221
12222/*
12223---
12224
12225name: Locale.no-NO.Date
12226
12227description: Date messages for Norwegian.
12228
12229license: MIT-style license
12230
12231authors:
12232  - Espen 'Rexxars' Hovlandsdal
12233
12234requires:
12235  - /Locale
12236
12237provides: [Locale.no-NO.Date]
12238
12239...
12240*/
12241
12242Locale.define('no-NO', 'Date', {
12243
12244	// Culture's date order: DD.MM.YYYY
12245	dateOrder: ['date', 'month', 'year'],
12246	shortDate: '%d.%m.%Y',
12247	shortTime: '%H:%M',
12248	AM: 'AM',
12249	PM: 'PM',
12250	firstDayOfWeek: 1,
12251
12252	lessThanMinuteAgo: 'kortere enn et minutt siden',
12253	minuteAgo: 'omtrent et minutt siden',
12254	minutesAgo: '{delta} minutter siden',
12255	hourAgo: 'omtrent en time siden',
12256	hoursAgo: 'omtrent {delta} timer siden',
12257	dayAgo: '{delta} dag siden',
12258	daysAgo: '{delta} dager siden'
12259
12260});
12261
12262
12263/*
12264---
12265
12266name: Locale.no-NO.Form.Validator
12267
12268description: Form Validator messages for Norwegian.
12269
12270license: MIT-style license
12271
12272authors:
12273  - Espen 'Rexxars' Hovlandsdal
12274
12275requires:
12276  - /Locale
12277
12278provides: [Locale.no-NO.Form.Validator]
12279
12280...
12281*/
12282
12283Locale.define('no-NO', 'FormValidator', {
12284
12285	required: 'Dette feltet er påkrevd.',
12286	minLength: 'Vennligst skriv inn minst {minLength} tegn (du skrev {length} tegn).',
12287	maxLength: 'Vennligst skriv inn maksimalt {maxLength} tegn (du skrev {length} tegn).',
12288	integer: 'Vennligst skriv inn et tall i dette feltet. Tall med desimaler (for eksempel 1,25) er ikke tillat.',
12289	numeric: 'Vennligst skriv inn kun numeriske verdier i dette feltet (for eksempel "1", "1.1", "-1" eller "-1.1").',
12290	digits: 'Vennligst bruk kun nummer og skilletegn i dette feltet.',
12291	alpha: 'Vennligst bruk kun bokstaver (a-z) i dette feltet. Ingen mellomrom eller andre tegn er tillat.',
12292	alphanum: 'Vennligst bruk kun bokstaver (a-z) eller nummer (0-9) i dette feltet. Ingen mellomrom eller andre tegn er tillat.',
12293	dateSuchAs: 'Vennligst skriv inn en gyldig dato, som {date}',
12294	dateInFormatMDY: 'Vennligst skriv inn en gyldig dato, i formatet MM/DD/YYYY (for eksempel "12/31/1999")',
12295	email: 'Vennligst skriv inn en gyldig epost-adresse. For eksempel "[email protected]".',
12296	url: 'Vennligst skriv inn en gyldig URL, for eksempel http://www.example.com.',
12297	currencyDollar: 'Vennligst fyll ut et gyldig $ beløp. For eksempel $100.00 .',
12298	oneRequired: 'Vennligst fyll ut noe i minst ett av disse feltene.',
12299	errorPrefix: 'Feil: ',
12300	warningPrefix: 'Advarsel: '
12301
12302});
12303
12304
12305/*
12306---
12307
12308name: Locale.pl-PL.Date
12309
12310description: Date messages for Polish.
12311
12312license: MIT-style license
12313
12314authors:
12315  - Oskar Krawczyk
12316
12317requires:
12318  - /Locale
12319
12320provides: [Locale.pl-PL.Date]
12321
12322...
12323*/
12324
12325Locale.define('pl-PL', 'Date', {
12326
12327	months: ['Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', 'Czerwiec', 'Lipiec', 'Sierpień', 'Wrzesień', 'Październik', 'Listopad', 'Grudzień'],
12328	months_abbr: ['sty', 'lut', 'mar', 'kwi', 'maj', 'cze', 'lip', 'sie', 'wrz', 'paź', 'lis', 'gru'],
12329	days: ['Niedziela', 'Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota'],
12330	days_abbr: ['niedz.', 'pon.', 'wt.', 'śr.', 'czw.', 'pt.', 'sob.'],
12331
12332	// Culture's date order: YYYY-MM-DD
12333	dateOrder: ['year', 'month', 'date'],
12334	shortDate: '%Y-%m-%d',
12335	shortTime: '%H:%M',
12336	AM: 'nad ranem',
12337	PM: 'po południu',
12338	firstDayOfWeek: 1,
12339
12340	// Date.Extras
12341	ordinal: function(dayOfMonth){
12342		return (dayOfMonth > 3 && dayOfMonth < 21) ? 'ty' : ['ty', 'szy', 'gi', 'ci', 'ty'][Math.min(dayOfMonth % 10, 4)];
12343	},
12344
12345	lessThanMinuteAgo: 'mniej niż minute temu',
12346	minuteAgo: 'około minutę temu',
12347	minutesAgo: '{delta} minut temu',
12348	hourAgo: 'około godzinę temu',
12349	hoursAgo: 'około {delta} godzin temu',
12350	dayAgo: 'Wczoraj',
12351	daysAgo: '{delta} dni temu',
12352
12353	lessThanMinuteUntil: 'za niecałą minutę',
12354	minuteUntil: 'za około minutę',
12355	minutesUntil: 'za {delta} minut',
12356	hourUntil: 'za około godzinę',
12357	hoursUntil: 'za około {delta} godzin',
12358	dayUntil: 'za 1 dzień',
12359	daysUntil: 'za {delta} dni'
12360
12361});
12362
12363
12364/*
12365---
12366
12367name: Locale.pl-PL.Form.Validator
12368
12369description: Form Validator messages for Polish.
12370
12371license: MIT-style license
12372
12373authors:
12374  - Oskar Krawczyk
12375
12376requires:
12377  - /Locale
12378
12379provides: [Locale.pl-PL.Form.Validator]
12380
12381...
12382*/
12383
12384Locale.define('pl-PL', 'FormValidator', {
12385
12386	required: 'To pole jest wymagane.',
12387	minLength: 'Wymagane jest przynajmniej {minLength} znaków (wpisanych zostało tylko {length}).',
12388	maxLength: 'Dozwolone jest nie więcej niż {maxLength} znaków (wpisanych zostało {length})',
12389	integer: 'To pole wymaga liczb całych. Liczby dziesiętne (np. 1.25) są niedozwolone.',
12390	numeric: 'Prosimy używać tylko numerycznych wartości w tym polu (np. "1", "1.1", "-1" lub "-1.1").',
12391	digits: 'Prosimy używać liczb oraz zankow punktuacyjnych w typ polu (dla przykładu, przy numerze telefonu myślniki i kropki są dozwolone).',
12392	alpha: 'Prosimy używać tylko liter (a-z) w tym polu. Spacje oraz inne znaki są niedozwolone.',
12393	alphanum: 'Prosimy używać tylko liter (a-z) lub liczb (0-9) w tym polu. Spacje oraz inne znaki są niedozwolone.',
12394	dateSuchAs: 'Prosimy podać prawidłową datę w formacie: {date}',
12395	dateInFormatMDY: 'Prosimy podać poprawną date w formacie DD.MM.RRRR (i.e. "12.01.2009")',
12396	email: 'Prosimy podać prawidłowy adres e-mail, np. "[email protected]".',
12397	url: 'Prosimy podać prawidłowy adres URL, np. http://www.example.com.',
12398	currencyDollar: 'Prosimy podać prawidłową sumę w PLN. Dla przykładu: 100.00 PLN.',
12399	oneRequired: 'Prosimy wypełnić chociaż jedno z pól.',
12400	errorPrefix: 'Błąd: ',
12401	warningPrefix: 'Uwaga: ',
12402
12403	// Form.Validator.Extras
12404	noSpace: 'W tym polu nie mogą znajdować się spacje.',
12405	reqChkByNode: 'Brak zaznaczonych elementów.',
12406	requiredChk: 'To pole jest wymagane.',
12407	reqChkByName: 'Prosimy wybrać z {label}.',
12408	match: 'To pole musi być takie samo jak {matchName}',
12409	startDate: 'data początkowa',
12410	endDate: 'data końcowa',
12411	currendDate: 'aktualna data',
12412	afterDate: 'Podana data poinna być taka sama lub po {label}.',
12413	beforeDate: 'Podana data poinna być taka sama lub przed {label}.',
12414	startMonth: 'Prosimy wybrać początkowy miesiąc.',
12415	sameMonth: 'Te dwie daty muszą być w zakresie tego samego miesiąca - wymagana jest zmiana któregoś z pól.'
12416
12417});
12418
12419
12420/*
12421---
12422
12423name: Locale.pt-PT.Date
12424
12425description: Date messages for Portuguese.
12426
12427license: MIT-style license
12428
12429authors:
12430  - Fabio Miranda Costa
12431
12432requires:
12433  - /Locale
12434
12435provides: [Locale.pt-PT.Date]
12436
12437...
12438*/
12439
12440Locale.define('pt-PT', 'Date', {
12441
12442	months: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'],
12443	months_abbr: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'],
12444	days: ['Domingo', 'Segunda-feira', 'Terça-feira', 'Quarta-feira', 'Quinta-feira', 'Sexta-feira', 'Sábado'],
12445	days_abbr: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'],
12446
12447	// Culture's date order: DD-MM-YYYY
12448	dateOrder: ['date', 'month', 'year'],
12449	shortDate: '%d-%m-%Y',
12450	shortTime: '%H:%M',
12451	AM: 'AM',
12452	PM: 'PM',
12453	firstDayOfWeek: 1,
12454
12455	// Date.Extras
12456	ordinal: 'º',
12457
12458	lessThanMinuteAgo: 'há menos de um minuto',
12459	minuteAgo: 'há cerca de um minuto',
12460	minutesAgo: 'há {delta} minutos',
12461	hourAgo: 'há cerca de uma hora',
12462	hoursAgo: 'há cerca de {delta} horas',
12463	dayAgo: 'há um dia',
12464	daysAgo: 'há {delta} dias',
12465	weekAgo: 'há uma semana',
12466	weeksAgo: 'há {delta} semanas',
12467	monthAgo: 'há um mês',
12468	monthsAgo: 'há {delta} meses',
12469	yearAgo: 'há um ano',
12470	yearsAgo: 'há {delta} anos',
12471
12472	lessThanMinuteUntil: 'em menos de um minuto',
12473	minuteUntil: 'em um minuto',
12474	minutesUntil: 'em {delta} minutos',
12475	hourUntil: 'em uma hora',
12476	hoursUntil: 'em {delta} horas',
12477	dayUntil: 'em um dia',
12478	daysUntil: 'em {delta} dias',
12479	weekUntil: 'em uma semana',
12480	weeksUntil: 'em {delta} semanas',
12481	monthUntil: 'em um mês',
12482	monthsUntil: 'em {delta} meses',
12483	yearUntil: 'em um ano',
12484	yearsUntil: 'em {delta} anos'
12485
12486});
12487
12488
12489/*
12490---
12491
12492name: Locale.pt-BR.Date
12493
12494description: Date messages for Portuguese (Brazil).
12495
12496license: MIT-style license
12497
12498authors:
12499  - Fabio Miranda Costa
12500
12501requires:
12502  - /Locale
12503  - /Locale.pt-PT.Date
12504
12505provides: [Locale.pt-BR.Date]
12506
12507...
12508*/
12509
12510Locale.define('pt-BR', 'Date', {
12511
12512	// Culture's date order: DD/MM/YYYY
12513	shortDate: '%d/%m/%Y'
12514
12515}).inherit('pt-PT', 'Date');
12516
12517
12518/*
12519---
12520
12521name: Locale.pt-BR.Form.Validator
12522
12523description: Form Validator messages for Portuguese (Brazil).
12524
12525license: MIT-style license
12526
12527authors:
12528  - Fábio Miranda Costa
12529
12530requires:
12531  - /Locale
12532
12533provides: [Locale.pt-BR.Form.Validator]
12534
12535...
12536*/
12537
12538Locale.define('pt-BR', 'FormValidator', {
12539
12540	required: 'Este campo é obrigatório.',
12541	minLength: 'Digite pelo menos {minLength} caracteres (tamanho atual: {length}).',
12542	maxLength: 'Não digite mais de {maxLength} caracteres (tamanho atual: {length}).',
12543	integer: 'Por favor digite apenas um número inteiro neste campo. Não são permitidos números decimais (por exemplo, 1,25).',
12544	numeric: 'Por favor digite apenas valores numéricos neste campo (por exemplo, "1" ou "1.1" ou "-1" ou "-1,1").',
12545	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).',
12546	alpha: 'Por favor use somente letras (a-z). Espaço e outros caracteres não são permitidos.',
12547	alphanum: 'Use somente letras (a-z) ou números (0-9) neste campo. Espaço e outros caracteres não são permitidos.',
12548	dateSuchAs: 'Digite uma data válida, como {date}',
12549	dateInFormatMDY: 'Digite uma data válida, como DD/MM/YYYY (por exemplo, "31/12/1999")',
12550	email: 'Digite um endereço de email válido. Por exemplo "[email protected]".',
12551	url: 'Digite uma URL válida. Exemplo: http://www.example.com.',
12552	currencyDollar: 'Digite um valor em dinheiro válido. Exemplo: R$100,00 .',
12553	oneRequired: 'Digite algo para pelo menos um desses campos.',
12554	errorPrefix: 'Erro: ',
12555	warningPrefix: 'Aviso: ',
12556
12557	// Form.Validator.Extras
12558	noSpace: 'Não é possível digitar espaços neste campo.',
12559	reqChkByNode: 'Não foi selecionado nenhum item.',
12560	requiredChk: 'Este campo é obrigatório.',
12561	reqChkByName: 'Por favor digite um {label}.',
12562	match: 'Este campo deve ser igual ao campo {matchName}.',
12563	startDate: 'a data inicial',
12564	endDate: 'a data final',
12565	currendDate: 'a data atual',
12566	afterDate: 'A data deve ser igual ou posterior a {label}.',
12567	beforeDate: 'A data deve ser igual ou anterior a {label}.',
12568	startMonth: 'Por favor selecione uma data inicial.',
12569	sameMonth: 'Estas duas datas devem ter o mesmo mês - você deve modificar uma das duas.',
12570	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.'
12571
12572});
12573
12574
12575/*
12576---
12577
12578name: Locale.pt-PT.Form.Validator
12579
12580description: Form Validator messages for Portuguese.
12581
12582license: MIT-style license
12583
12584authors:
12585  - Miquel Hudin
12586
12587requires:
12588  - /Locale
12589
12590provides: [Locale.pt-PT.Form.Validator]
12591
12592...
12593*/
12594
12595Locale.define('pt-PT', 'FormValidator', {
12596
12597	required: 'Este campo é necessário.',
12598	minLength: 'Digite pelo menos{minLength} caracteres (comprimento {length} caracteres).',
12599	maxLength: 'Não insira mais de {maxLength} caracteres (comprimento {length} caracteres).',
12600	integer: 'Digite um número inteiro neste domínio. Com números decimais (por exemplo, 1,25), não são permitidas.',
12601	numeric: 'Digite apenas valores numéricos neste domínio (p.ex., "1" ou "1.1" ou "-1" ou "-1,1").',
12602	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).',
12603	alpha: 'Por favor use somente letras (a-z), com nesta área. Não utilize espaços nem outros caracteres são permitidos.',
12604	alphanum: 'Use somente letras (a-z) ou números (0-9) neste campo. Não utilize espaços nem outros caracteres são permitidos.',
12605	dateSuchAs: 'Digite uma data válida, como {date}',
12606	dateInFormatMDY: 'Digite uma data válida, como DD/MM/YYYY (p.ex. "31/12/1999")',
12607	email: 'Digite um endereço de email válido. Por exemplo "[email protected]".',
12608	url: 'Digite uma URL válida, como http://www.example.com.',
12609	currencyDollar: 'Digite um valor válido $. Por exemplo $ 100,00. ',
12610	oneRequired: 'Digite algo para pelo menos um desses insumos.',
12611	errorPrefix: 'Erro: ',
12612	warningPrefix: 'Aviso: '
12613
12614});
12615
12616
12617/*
12618---
12619
12620name: Locale.ru-RU-unicode.Date
12621
12622description: Date messages for Russian (utf-8).
12623
12624license: MIT-style license
12625
12626authors:
12627  - Evstigneev Pavel
12628  - Kuryanovich Egor
12629
12630requires:
12631  - /Locale
12632
12633provides: [Locale.ru-RU.Date]
12634
12635...
12636*/
12637
12638(function(){
12639
12640// Russian language pluralization rules, taken from CLDR project, http://unicode.org/cldr/
12641// one -> n mod 10 is 1 and n mod 100 is not 11;
12642// few -> n mod 10 in 2..4 and n mod 100 not in 12..14;
12643// many -> n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14;
12644// other -> everything else (example 3.14)
12645var pluralize = function (n, one, few, many, other){
12646	var modulo10 = n % 10,
12647		modulo100 = n % 100;
12648
12649	if (modulo10 == 1 && modulo100 != 11){
12650		return one;
12651	} else if ((modulo10 == 2 || modulo10 == 3 || modulo10 == 4) && !(modulo100 == 12 || modulo100 == 13 || modulo100 == 14)){
12652		return few;
12653	} else if (modulo10 == 0 || (modulo10 == 5 || modulo10 == 6 || modulo10 == 7 || modulo10 == 8 || modulo10 == 9) || (modulo100 == 11 || modulo100 == 12 || modulo100 == 13 || modulo100 == 14)){
12654		return many;
12655	} else {
12656		return other;
12657	}
12658};
12659
12660Locale.define('ru-RU', 'Date', {
12661
12662	months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],
12663	months_abbr: ['янв', 'февр', 'март', 'апр', 'май','июнь','июль','авг','сент','окт','нояб','дек'],
12664	days: ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'],
12665	days_abbr: ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'],
12666
12667	// Culture's date order: DD.MM.YYYY
12668	dateOrder: ['date', 'month', 'year'],
12669	shortDate: '%d.%m.%Y',
12670	shortTime: '%H:%M',
12671	AM: 'AM',
12672	PM: 'PM',
12673	firstDayOfWeek: 1,
12674
12675	// Date.Extras
12676	ordinal: '',
12677
12678	lessThanMinuteAgo: 'меньше минуты назад',
12679	minuteAgo: 'минуту назад',
12680	minutesAgo: function(delta){ return '{delta} ' + pluralize(delta, 'минуту', 'минуты', 'минут') + ' назад'; },
12681	hourAgo: 'час назад',
12682	hoursAgo: function(delta){ return '{delta} ' + pluralize(delta, 'час', 'часа', 'часов') + ' назад'; },
12683	dayAgo: 'вчера',
12684	daysAgo: function(delta){ return '{delta} ' + pluralize(delta, 'день', 'дня', 'дней') + ' назад'; },
12685	weekAgo: 'неделю назад',
12686	weeksAgo: function(delta){ return '{delta} ' + pluralize(delta, 'неделя', 'недели', 'недель') + ' назад'; },
12687	monthAgo: 'месяц назад',
12688	monthsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'месяц', 'месяца', 'месецев') + ' назад'; },
12689	yearAgo: 'год назад',
12690	yearsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'год', 'года', 'лет') + ' назад'; },
12691
12692	lessThanMinuteUntil: 'меньше чем через минуту',
12693	minuteUntil: 'через минуту',
12694	minutesUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'час', 'часа', 'часов') + ''; },
12695	hourUntil: 'через час',
12696	hoursUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'час', 'часа', 'часов') + ''; },
12697	dayUntil: 'завтра',
12698	daysUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'день', 'дня', 'дней') + ''; },
12699	weekUntil: 'через неделю',
12700	weeksUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'неделю', 'недели', 'недель') + ''; },
12701	monthUntil: 'через месяц',
12702	monthsUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'месяц', 'месяца', 'месецев') + ''; },
12703	yearUntil: 'через',
12704	yearsUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'год', 'года', 'лет') + ''; }
12705
12706});
12707
12708
12709
12710})();
12711
12712
12713/*
12714---
12715
12716name: Locale.ru-RU-unicode.Form.Validator
12717
12718description: Form Validator messages for Russian (utf-8).
12719
12720license: MIT-style license
12721
12722authors:
12723  - Chernodarov Egor
12724
12725requires:
12726  - /Locale
12727
12728provides: [Locale.ru-RU.Form.Validator]
12729
12730...
12731*/
12732
12733Locale.define('ru-RU', 'FormValidator', {
12734
12735	required: 'Это поле обязательно к заполнению.',
12736	minLength: 'Пожалуйста, введите хотя бы {minLength} символов (Вы ввели {length}).',
12737	maxLength: 'Пожалуйста, введите не больше {maxLength} символов (Вы ввели {length}).',
12738	integer: 'Пожалуйста, введите в это поле число. Дробные числа (например 1.25) тут не разрешены.',
12739	numeric: 'Пожалуйста, введите в это поле число (например "1" или "1.1", или "-1", или "-1.1").',
12740	digits: 'В этом поле Вы можете использовать только цифры и знаки пунктуации (например, телефонный номер со знаками дефиса или с точками).',
12741	alpha: 'В этом поле можно использовать только латинские буквы (a-z). Пробелы и другие символы запрещены.',
12742	alphanum: 'В этом поле можно использовать только латинские буквы (a-z) и цифры (0-9). Пробелы и другие символы запрещены.',
12743	dateSuchAs: 'Пожалуйста, введите корректную дату {date}',
12744	dateInFormatMDY: 'Пожалуйста, введите дату в формате ММ/ДД/ГГГГ (например "12/31/1999")',
12745	email: 'Пожалуйста, введите корректный емейл-адрес. Для примера "[email protected]".',
12746	url: 'Пожалуйста, введите правильную ссылку вида http://www.example.com.',
12747	currencyDollar: 'Пожалуйста, введите сумму в долларах. Например: $100.00 .',
12748	oneRequired: 'Пожалуйста, выберите хоть что-нибудь в одном из этих полей.',
12749	errorPrefix: 'Ошибка: ',
12750	warningPrefix: 'Внимание: '
12751
12752});
12753
12754
12755
12756
12757/*
12758---
12759
12760name: Locale.si-SI.Date
12761
12762description: Date messages for Slovenian.
12763
12764license: MIT-style license
12765
12766authors:
12767  - Radovan Lozej
12768
12769requires:
12770  - /Locale
12771
12772provides: [Locale.si-SI.Date]
12773
12774...
12775*/
12776
12777(function(){
12778
12779var pluralize = function(n, one, two, three, other){
12780	return (n >= 1 && n <= 3) ? arguments[n] : other;
12781};
12782
12783Locale.define('si-SI', 'Date', {
12784
12785	months: ['januar', 'februar', 'marec', 'april', 'maj', 'junij', 'julij', 'avgust', 'september', 'oktober', 'november', 'december'],
12786	months_abbr: ['jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'avg', 'sep', 'okt', 'nov', 'dec'],
12787	days: ['nedelja', 'ponedeljek', 'torek', 'sreda', 'četrtek', 'petek', 'sobota'],
12788	days_abbr: ['ned', 'pon', 'tor', 'sre', 'čet', 'pet', 'sob'],
12789
12790	// Culture's date order: DD.MM.YYYY
12791	dateOrder: ['date', 'month', 'year'],
12792	shortDate: '%d.%m.%Y',
12793	shortTime: '%H.%M',
12794	AM: 'AM',
12795	PM: 'PM',
12796	firstDayOfWeek: 1,
12797
12798	// Date.Extras
12799	ordinal: '.',
12800
12801	lessThanMinuteAgo: 'manj kot minuto nazaj',
12802	minuteAgo: 'minuto nazaj',
12803	minutesAgo: function(delta){ return '{delta} ' + pluralize(delta, 'minuto', 'minuti', 'minute', 'minut') + ' nazaj'; },
12804	hourAgo: 'uro nazaj',
12805	hoursAgo: function(delta){ return '{delta} ' + pluralize(delta, 'uro', 'uri', 'ure', 'ur') + ' nazaj'; },
12806	dayAgo: 'dan nazaj',
12807	daysAgo: function(delta){ return '{delta} ' + pluralize(delta, 'dan', 'dneva', 'dni', 'dni') + ' nazaj'; },
12808	weekAgo: 'teden nazaj',
12809	weeksAgo: function(delta){ return '{delta} ' + pluralize(delta, 'teden', 'tedna', 'tedne', 'tednov') + ' nazaj'; },
12810	monthAgo: 'mesec nazaj',
12811	monthsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'mesec', 'meseca', 'mesece', 'mesecov') + ' nazaj'; },
12812	yearthAgo: 'leto nazaj',
12813	yearsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'leto', 'leti', 'leta', 'let') + ' nazaj'; },
12814
12815	lessThanMinuteUntil: 'še manj kot minuto',
12816	minuteUntil: 'še minuta',
12817	minutesUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'minuta', 'minuti', 'minute', 'minut'); },
12818	hourUntil: 'še ura',
12819	hoursUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'ura', 'uri', 'ure', 'ur'); },
12820	dayUntil: 'še dan',
12821	daysUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'dan', 'dneva', 'dnevi', 'dni'); },
12822	weekUntil: 'še tedn',
12823	weeksUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'teden', 'tedna', 'tedni', 'tednov'); },
12824	monthUntil: 'še mesec',
12825	monthsUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'mesec', 'meseca', 'meseci', 'mesecov'); },
12826	yearUntil: 'še leto',
12827	yearsUntil: function(delta){ return 'še {delta} ' + pluralize(delta, 'leto', 'leti', 'leta', 'let'); }
12828
12829});
12830
12831})();
12832
12833
12834/*
12835---
12836
12837name: Locale.si-SI.Form.Validator
12838
12839description: Form Validator messages for Slovenian.
12840
12841license: MIT-style license
12842
12843authors:
12844  - Radovan Lozej
12845
12846requires:
12847  - /Locale
12848
12849provides: [Locale.si-SI.Form.Validator]
12850
12851...
12852*/
12853
12854Locale.define('si-SI', 'FormValidator', {
12855
12856	required: 'To polje je obvezno',
12857	minLength: 'Prosim, vnesite vsaj {minLength} znakov (vnesli ste {length} znakov).',
12858	maxLength: 'Prosim, ne vnesite več kot {maxLength} znakov (vnesli ste {length} znakov).',
12859	integer: 'Prosim, vnesite celo število. Decimalna števila (kot 1,25) niso dovoljena.',
12860	numeric: 'Prosim, vnesite samo numerične vrednosti (kot "1" ali "1.1" ali "-1" ali "-1.1").',
12861	digits: 'Prosim, uporabite številke in ločila le na tem polju (na primer, dovoljena je telefonska številka z pomišlaji ali pikami).',
12862	alpha: 'Prosim, uporabite le črke v tem plju. Presledki in drugi znaki niso dovoljeni.',
12863	alphanum: 'Prosim, uporabite samo črke ali številke v tem polju. Presledki in drugi znaki niso dovoljeni.',
12864	dateSuchAs: 'Prosim, vnesite pravilen datum kot {date}',
12865	dateInFormatMDY: 'Prosim, vnesite pravilen datum kot MM.DD.YYYY (primer "12.31.1999")',
12866	email: 'Prosim, vnesite pravilen email naslov. Na primer "[email protected]".',
12867	url: 'Prosim, vnesite pravilen URL kot http://www.example.com.',
12868	currencyDollar: 'Prosim, vnesit epravilno vrednost €. Primer 100,00€ .',
12869	oneRequired: 'Prosimo, vnesite nekaj za vsaj eno izmed teh polj.',
12870	errorPrefix: 'Napaka: ',
12871	warningPrefix: 'Opozorilo: ',
12872
12873	// Form.Validator.Extras
12874	noSpace: 'To vnosno polje ne dopušča presledkov.',
12875	reqChkByNode: 'Nič niste izbrali.',
12876	requiredChk: 'To polje je obvezno',
12877	reqChkByName: 'Prosim, izberite {label}.',
12878	match: 'To polje se mora ujemati z poljem {matchName}',
12879	startDate: 'datum začetka',
12880	endDate: 'datum konca',
12881	currendDate: 'trenuten datum',
12882	afterDate: 'Datum bi moral biti isti ali po {label}.',
12883	beforeDate: 'Datum bi moral biti isti ali pred {label}.',
12884	startMonth: 'Prosim, vnesite začetni datum',
12885	sameMonth: 'Ta dva datuma morata biti v istem mesecu - premeniti morate eno ali drugo.',
12886	creditcard: 'Številka kreditne kartice ni pravilna. Preverite številko ali poskusite še enkrat. Vnešenih {length} znakov.'
12887
12888});
12889
12890
12891/*
12892---
12893
12894name: Locale.sv-SE.Date
12895
12896description: Date messages for Swedish.
12897
12898license: MIT-style license
12899
12900authors:
12901  - Martin Lundgren
12902
12903requires:
12904  - /Locale
12905
12906provides: [Locale.sv-SE.Date]
12907
12908...
12909*/
12910
12911Locale.define('sv-SE', 'Date', {
12912
12913	months: ['januari', 'februari', 'mars', 'april', 'maj', 'juni', 'juli', 'augusti', 'september', 'oktober', 'november', 'december'],
12914	months_abbr: ['jan', 'feb', 'mar', 'apr', 'maj', 'jun', 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'],
12915	days: ['söndag', 'måndag', 'tisdag', 'onsdag', 'torsdag', 'fredag', 'lördag'],
12916	days_abbr: ['sön', 'mån', 'tis', 'ons', 'tor', 'fre', 'lör'],
12917
12918	// Culture's date order: YYYY-MM-DD
12919	dateOrder: ['year', 'month', 'date'],
12920	shortDate: '%Y-%m-%d',
12921	shortTime: '%H:%M',
12922	AM: '',
12923	PM: '',
12924	firstDayOfWeek: 1,
12925
12926	// Date.Extras
12927	ordinal: '',
12928
12929	lessThanMinuteAgo: 'mindre än en minut sedan',
12930	minuteAgo: 'ungefär en minut sedan',
12931	minutesAgo: '{delta} minuter sedan',
12932	hourAgo: 'ungefär en timme sedan',
12933	hoursAgo: 'ungefär {delta} timmar sedan',
12934	dayAgo: '1 dag sedan',
12935	daysAgo: '{delta} dagar sedan',
12936
12937	lessThanMinuteUntil: 'mindre än en minut sedan',
12938	minuteUntil: 'ungefär en minut sedan',
12939	minutesUntil: '{delta} minuter sedan',
12940	hourUntil: 'ungefär en timme sedan',
12941	hoursUntil: 'ungefär {delta} timmar sedan',
12942	dayUntil: '1 dag sedan',
12943	daysUntil: '{delta} dagar sedan'
12944
12945});
12946
12947
12948/*
12949---
12950
12951name: Locale.sv-SE.Form.Validator
12952
12953description: Form Validator messages for Swedish.
12954
12955license: MIT-style license
12956
12957authors:
12958  - Martin Lundgren
12959
12960requires:
12961  - /Locale
12962
12963provides: [Locale.sv-SE.Form.Validator]
12964
12965...
12966*/
12967
12968Locale.define('sv-SE', 'FormValidator', {
12969
12970	required: 'Fältet är obligatoriskt.',
12971	minLength: 'Ange minst {minLength} tecken (du angav {length} tecken).',
12972	maxLength: 'Ange högst {maxLength} tecken (du angav {length} tecken). ',
12973	integer: 'Ange ett heltal i fältet. Tal med decimaler (t.ex. 1,25) är inte tillåtna.',
12974	numeric: 'Ange endast numeriska värden i detta fält (t.ex. "1" eller "1.1" eller "-1" eller "-1,1").',
12975	digits: 'Använd endast siffror och skiljetecken i detta fält (till exempel ett telefonnummer med bindestreck tillåtet).',
12976	alpha: 'Använd endast bokstäver (a-ö) i detta fält. Inga mellanslag eller andra tecken är tillåtna.',
12977	alphanum: 'Använd endast bokstäver (a-ö) och siffror (0-9) i detta fält. Inga mellanslag eller andra tecken är tillåtna.',
12978	dateSuchAs: 'Ange ett giltigt datum som t.ex. {date}',
12979	dateInFormatMDY: 'Ange ett giltigt datum som t.ex. YYYY-MM-DD (i.e. "1999-12-31")',
12980	email: 'Ange en giltig e-postadress. Till exempel "[email protected]".',
12981	url: 'Ange en giltig webbadress som http://www.example.com.',
12982	currencyDollar: 'Ange en giltig belopp. Exempelvis 100,00.',
12983	oneRequired: 'Vänligen ange minst ett av dessa alternativ.',
12984	errorPrefix: 'Fel: ',
12985	warningPrefix: 'Varning: ',
12986
12987	// Form.Validator.Extras
12988	noSpace: 'Det får inte finnas några mellanslag i detta fält.',
12989	reqChkByNode: 'Inga objekt är valda.',
12990	requiredChk: 'Detta är ett obligatoriskt fält.',
12991	reqChkByName: 'Välj en {label}.',
12992	match: 'Detta fält måste matcha {matchName}',
12993	startDate: 'startdatumet',
12994	endDate: 'slutdatum',
12995	currendDate: 'dagens datum',
12996	afterDate: 'Datumet bör vara samma eller senare än {label}.',
12997	beforeDate: 'Datumet bör vara samma eller tidigare än {label}.',
12998	startMonth: 'Välj en start månad',
12999	sameMonth: 'Dessa två datum måste vara i samma månad - du måste ändra det ena eller det andra.'
13000
13001});
13002
13003
13004/*
13005---
13006
13007name: Locale.uk-UA.Date
13008
13009description: Date messages for Ukrainian (utf-8).
13010
13011license: MIT-style license
13012
13013authors:
13014  - Slik
13015
13016requires:
13017  - /Locale
13018
13019provides: [Locale.uk-UA.Date]
13020
13021...
13022*/
13023
13024(function(){
13025
13026var pluralize = function(n, one, few, many, other){
13027	var d = (n / 10).toInt(),
13028		z = n % 10,
13029		s = (n / 100).toInt();
13030
13031	if (d == 1 && n > 10) return many;
13032	if (z == 1) return one;
13033	if (z > 0 && z < 5) return few;
13034	return many;
13035};
13036
13037Locale.define('uk-UA', 'Date', {
13038
13039	months: ['Січень', 'Лютий', 'Березень', 'Квітень', 'Травень', 'Червень', 'Липень', 'Серпень', 'Вересень', 'Жовтень', 'Листопад', 'Грудень'],
13040	months_abbr: ['Січ', 'Лют', 'Бер', 'Квіт', 'Трав', 'Черв', 'Лип', 'Серп', 'Вер', 'Жовт', 'Лист', 'Груд' ],
13041	days: ['Неділя', 'Понеділок', 'Вівторок', 'Середа', 'Четвер', "П'ятниця", 'Субота'],
13042	days_abbr: ['Нд', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'],
13043
13044	// Culture's date order: DD/MM/YYYY
13045	dateOrder: ['date', 'month', 'year'],
13046	shortDate: '%d/%m/%Y',
13047	shortTime: '%H:%M',
13048	AM: 'до полудня',
13049	PM: 'по полудню',
13050	firstDayOfWeek: 1,
13051
13052	// Date.Extras
13053	ordinal: '',
13054
13055	lessThanMinuteAgo: 'меньше хвилини тому',
13056	minuteAgo: 'хвилину тому',
13057	minutesAgo: function(delta){ return '{delta} ' + pluralize(delta, 'хвилину', 'хвилини', 'хвилин') + ' тому'; },
13058	hourAgo: 'годину тому',
13059	hoursAgo: function(delta){ return '{delta} ' + pluralize(delta, 'годину', 'години', 'годин') + ' тому'; },
13060	dayAgo: 'вчора',
13061	daysAgo: function(delta){ return '{delta} ' + pluralize(delta, 'день', 'дня', 'днів') + ' тому'; },
13062	weekAgo: 'тиждень тому',
13063	weeksAgo: function(delta){ return '{delta} ' + pluralize(delta, 'тиждень', 'тижні', 'тижнів') + ' тому'; },
13064	monthAgo: 'місяць тому',
13065	monthsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'місяць', 'місяці', 'місяців') + ' тому'; },
13066	yearAgo: 'рік тому',
13067	yearsAgo: function(delta){ return '{delta} ' + pluralize(delta, 'рік', 'роки', 'років') + ' тому'; },
13068
13069	lessThanMinuteUntil: 'за мить',
13070	minuteUntil: 'через хвилину',
13071	minutesUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'хвилину', 'хвилини', 'хвилин'); },
13072	hourUntil: 'через годину',
13073	hoursUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'годину', 'години', 'годин'); },
13074	dayUntil: 'завтра',
13075	daysUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'день', 'дня', 'днів'); },
13076	weekUntil: 'через тиждень',
13077	weeksUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'тиждень', 'тижні', 'тижнів'); },
13078	monthUntil: 'через місяць',
13079	monthesUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'місяць', 'місяці', 'місяців'); },
13080	yearUntil: 'через рік',
13081	yearsUntil: function(delta){ return 'через {delta} ' + pluralize(delta, 'рік', 'роки', 'років'); }
13082
13083});
13084
13085})();
13086
13087
13088/*
13089---
13090
13091name: Locale.uk-UA.Form.Validator
13092
13093description: Form Validator messages for Ukrainian (utf-8).
13094
13095license: MIT-style license
13096
13097authors:
13098  - Slik
13099
13100requires:
13101  - /Locale
13102
13103provides: [Locale.uk-UA.Form.Validator]
13104
13105...
13106*/
13107
13108Locale.define('uk-UA', 'FormValidator', {
13109
13110	required: 'Це поле повинне бути заповненим.',
13111	minLength: 'Введіть хоча б {minLength} символів (Ви ввели {length}).',
13112	maxLength: 'Кількість символів не може бути більше {maxLength} (Ви ввели {length}).',
13113	integer: 'Введіть в це поле число. Дробові числа (наприклад 1.25) не дозволені.',
13114	numeric: 'Введіть в це поле число (наприклад "1" або "1.1", або "-1", або "-1.1").',
13115	digits: 'В цьому полі ви можете використовувати лише цифри і знаки пунктіації (наприклад, телефонний номер з знаками дефізу або з крапками).',
13116	alpha: 'В цьому полі можна використовувати лише латинські літери (a-z). Пробіли і інші символи заборонені.',
13117	alphanum: 'В цьому полі можна використовувати лише латинські літери (a-z) і цифри (0-9). Пробіли і інші символи заборонені.',
13118	dateSuchAs: 'Введіть коректну дату {date}.',
13119	dateInFormatMDY: 'Введіть дату в форматі ММ/ДД/РРРР (наприклад "12/31/2009").',
13120	email: 'Введіть коректну адресу електронної пошти (наприклад "[email protected]").',
13121	url: 'Введіть коректне інтернет-посилання (наприклад http://www.example.com).',
13122	currencyDollar: 'Введіть суму в доларах (наприклад "$100.00").',
13123	oneRequired: 'Заповніть одне з полів.',
13124	errorPrefix: 'Помилка: ',
13125	warningPrefix: 'Увага: ',
13126
13127	noSpace: 'Пробіли заборонені.',
13128	reqChkByNode: 'Не відмічено жодного варіанту.',
13129	requiredChk: 'Це поле повинне бути віміченим.',
13130	reqChkByName: 'Будь ласка, відмітьте {label}.',
13131	match: 'Це поле повинно відповідати {matchName}',
13132	startDate: 'початкова дата',
13133	endDate: 'кінцева дата',
13134	currendDate: 'сьогоднішня дата',
13135	afterDate: 'Ця дата повинна бути такою ж, або пізнішою за {label}.',
13136	beforeDate: 'Ця дата повинна бути такою ж, або ранішою за {label}.',
13137	startMonth: 'Будь ласка, виберіть початковий місяць',
13138	sameMonth: 'Ці дати повинні відноситись одного і того ж місяця. Будь ласка, змініть одну з них.',
13139	creditcard: 'Номер кредитної карти введений неправильно. Будь ласка, перевірте його. Введено {length} символів.'
13140
13141});
13142
13143
13144/*
13145---
13146
13147name: Locale.zh-CH.Date
13148
13149description: Date messages for Chinese (simplified and traditional).
13150
13151license: MIT-style license
13152
13153authors:
13154  - YMind Chan
13155
13156requires:
13157  - /Locale
13158
13159provides: [Locale.zh-CH.Date]
13160
13161...
13162*/
13163
13164// Simplified Chinese
13165Locale.define('zh-CHS', 'Date', {
13166
13167	months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
13168	months_abbr: ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'],
13169	days: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
13170	days_abbr: ['日', '一', '二', '三', '四', '五', '六'],
13171
13172	// Culture's date order: YYYY-MM-DD
13173	dateOrder: ['year', 'month', 'date'],
13174	shortDate: '%Y-%m-%d',
13175	shortTime: '%I:%M%p',
13176	AM: 'AM',
13177	PM: 'PM',
13178	firstDayOfWeek: 1,
13179
13180	// Date.Extras
13181	ordinal: '',
13182
13183	lessThanMinuteAgo: '不到1分钟前',
13184	minuteAgo: '大约1分钟前',
13185	minutesAgo: '{delta}分钟之前',
13186	hourAgo: '大约1小时前',
13187	hoursAgo: '大约{delta}小时前',
13188	dayAgo: '1天前',
13189	daysAgo: '{delta}天前',
13190	weekAgo: '1星期前',
13191	weeksAgo: '{delta}星期前',
13192	monthAgo: '1个月前',
13193	monthsAgo: '{delta}个月前',
13194	yearAgo: '1年前',
13195	yearsAgo: '{delta}年前',
13196
13197	lessThanMinuteUntil: '从现在开始不到1分钟',
13198	minuteUntil: '从现在开始約1分钟',
13199	minutesUntil: '从现在开始约{delta}分钟',
13200	hourUntil: '从现在开始1小时',
13201	hoursUntil: '从现在开始约{delta}小时',
13202	dayUntil: '从现在开始1天',
13203	daysUntil: '从现在开始{delta}天',
13204	weekUntil: '从现在开始1星期',
13205	weeksUntil: '从现在开始{delta}星期',
13206	monthUntil: '从现在开始一个月',
13207	monthsUntil: '从现在开始{delta}个月',
13208	yearUntil: '从现在开始1年',
13209	yearsUntil: '从现在开始{delta}年'
13210
13211});
13212
13213// Traditional Chinese
13214Locale.define('zh-CHT', 'Date', {
13215
13216	months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
13217	months_abbr: ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'],
13218	days: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
13219	days_abbr: ['日', '一', '二', '三', '四', '五', '六'],
13220
13221	// Culture's date order: YYYY-MM-DD
13222	dateOrder: ['year', 'month', 'date'],
13223	shortDate: '%Y-%m-%d',
13224	shortTime: '%I:%M%p',
13225	AM: 'AM',
13226	PM: 'PM',
13227	firstDayOfWeek: 1,
13228
13229	// Date.Extras
13230	ordinal: '',
13231
13232	lessThanMinuteAgo: '不到1分鐘前',
13233	minuteAgo: '大約1分鐘前',
13234	minutesAgo: '{delta}分鐘之前',
13235	hourAgo: '大約1小時前',
13236	hoursAgo: '大約{delta}小時前',
13237	dayAgo: '1天前',
13238	daysAgo: '{delta}天前',
13239	weekAgo: '1星期前',
13240	weeksAgo: '{delta}星期前',
13241	monthAgo: '1个月前',
13242	monthsAgo: '{delta}个月前',
13243	yearAgo: '1年前',
13244	yearsAgo: '{delta}年前',
13245
13246	lessThanMinuteUntil: '從現在開始不到1分鐘',
13247	minuteUntil: '從現在開始約1分鐘',
13248	minutesUntil: '從現在開始約{delta}分鐘',
13249	hourUntil: '從現在開始1小時',
13250	hoursUntil: '從現在開始約{delta}小時',
13251	dayUntil: '從現在開始1天',
13252	daysUntil: '從現在開始{delta}天',
13253	weekUntil: '從現在開始1星期',
13254	weeksUntil: '從現在開始{delta}星期',
13255	monthUntil: '從現在開始一個月',
13256	monthsUntil: '從現在開始{delta}個月',
13257	yearUntil: '從現在開始1年',
13258	yearsUntil: '從現在開始{delta}年'
13259
13260});
13261
13262
13263/*
13264---
13265
13266name: Locale.zh-CH.Form.Validator
13267
13268description: Form Validator messages for Chinese (simplified and traditional).
13269
13270license: MIT-style license
13271
13272authors:
13273  - YMind Chan
13274
13275requires:
13276  - /Locale
13277  - /Form.Validator
13278
13279provides: [Form.zh-CH.Form.Validator, Form.Validator.CurrencyYuanValidator]
13280
13281...
13282*/
13283
13284// Simplified Chinese
13285Locale.define('zh-CHS', 'FormValidator', {
13286
13287	required: '此项必填。',
13288	minLength: '请至少输入 {minLength} 个字符 (已输入 {length} 个)。',
13289	maxLength: '最多只能输入 {maxLength} 个字符 (已输入 {length} 个)。',
13290	integer: '请输入一个整数,不能包含小数点。例如:"1", "200"。',
13291	numeric: '请输入一个数字,例如:"1", "1.1", "-1", "-1.1"。',
13292	digits: '请输入由数字和标点符号组成的内容。例如电话号码。',
13293	alpha: '请输入 A-Z 的 26 个字母,不能包含空格或任何其他字符。',
13294	alphanum: '请输入 A-Z 的 26 个字母或 0-9 的 10 个数字,不能包含空格或任何其他字符。',
13295	dateSuchAs: '请输入合法的日期格式,如:{date}。',
13296	dateInFormatMDY: '请输入合法的日期格式,例如:YYYY-MM-DD ("2010-12-31")。',
13297	email: '请输入合法的电子信箱地址,例如:"[email protected]"。',
13298	url: '请输入合法的 Url 地址,例如:http://www.example.com。',
13299	currencyDollar: '请输入合法的货币符号,例如:¥100.0',
13300	oneRequired: '请至少选择一项。',
13301	errorPrefix: '错误:',
13302	warningPrefix: '警告:',
13303
13304	// Form.Validator.Extras
13305	noSpace: '不能包含空格。',
13306	reqChkByNode: '未选择任何内容。',
13307	requiredChk: '此项必填。',
13308	reqChkByName: '请选择 {label}.',
13309	match: '必须与{matchName}相匹配',
13310	startDate: '起始日期',
13311	endDate: '结束日期',
13312	currendDate: '当前日期',
13313	afterDate: '日期必须等于或晚于 {label}.',
13314	beforeDate: '日期必须早于或等于 {label}.',
13315	startMonth: '请选择起始月份',
13316	sameMonth: '您必须修改两个日期中的一个,以确保它们在同一月份。',
13317	creditcard: '您输入的信用卡号码不正确。当前已输入{length}个字符。'
13318
13319});
13320
13321// Traditional Chinese
13322Locale.define('zh-CHT', 'FormValidator', {
13323
13324	required: '此項必填。 ',
13325	minLength: '請至少輸入{minLength} 個字符(已輸入{length} 個)。 ',
13326	maxLength: '最多只能輸入{maxLength} 個字符(已輸入{length} 個)。 ',
13327	integer: '請輸入一個整數,不能包含小數點。例如:"1", "200"。 ',
13328	numeric: '請輸入一個數字,例如:"1", "1.1", "-1", "-1.1"。 ',
13329	digits: '請輸入由數字和標點符號組成的內容。例如電話號碼。 ',
13330	alpha: '請輸入AZ 的26 個字母,不能包含空格或任何其他字符。 ',
13331	alphanum: '請輸入AZ 的26 個字母或0-9 的10 個數字,不能包含空格或任何其他字符。 ',
13332	dateSuchAs: '請輸入合法的日期格式,如:{date}。 ',
13333	dateInFormatMDY: '請輸入合法的日期格式,例如:YYYY-MM-DD ("2010-12-31")。 ',
13334	email: '請輸入合法的電子信箱地址,例如:"[email protected]"。 ',
13335	url: '請輸入合法的Url 地址,例如:http://www.example.com。 ',
13336	currencyDollar: '請輸入合法的貨幣符號,例如:¥100.0',
13337	oneRequired: '請至少選擇一項。 ',
13338	errorPrefix: '錯誤:',
13339	warningPrefix: '警告:',
13340
13341	// Form.Validator.Extras
13342	noSpace: '不能包含空格。 ',
13343	reqChkByNode: '未選擇任何內容。 ',
13344	requiredChk: '此項必填。 ',
13345	reqChkByName: '請選擇 {label}.',
13346	match: '必須與{matchName}相匹配',
13347	startDate: '起始日期',
13348	endDate: '結束日期',
13349	currendDate: '當前日期',
13350	afterDate: '日期必須等於或晚於{label}.',
13351	beforeDate: '日期必須早於或等於{label}.',
13352	startMonth: '請選擇起始月份',
13353	sameMonth: '您必須修改兩個日期中的一個,以確保它們在同一月份。 ',
13354	creditcard: '您輸入的信用卡號碼不正確。當前已輸入{length}個字符。 '
13355
13356});
13357
13358Form.Validator.add('validate-currency-yuan', {
13359
13360	errorMsg: function(){
13361		return Form.Validator.getMsg('currencyYuan');
13362	},
13363
13364	test: function(element){
13365		// [ï¿¥]1[##][,###]+[.##]
13366		// [ï¿¥]1###+[.##]
13367		// [ï¿¥]0.##
13368		// [ï¿¥].##
13369		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'));
13370	}
13371
13372});
13373

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.