Merge branch 'jordan' of ssh://git.onelab.eu/git/myslice into jordan
[myslice.git] / plugins / code_editor / moo-clientcide-1.3.js
1
2 //This library: http://dev.clientcide.com/depender/build?download=true&version=Clientcide+3.1.0&require=Core%2FBrowser&require=Core%2FClass.Extras&require=Core%2FClass&require=Core%2FCore&require=Core%2FElement.Delegation&require=Core%2FElement.Dimensions&require=Core%2FElement.Event&require=Core%2FElement.Style&require=Core%2FElement&require=Core%2FFx.CSS&require=Core%2FFx.Morph&require=Core%2FFx.Transitions&require=Core%2FFx.Tween&require=Core%2FFx&require=Core%2FRequest.HTML&require=Core%2FRequest.JSON&require=Core%2FRequest&require=Core%2FSlick.Finder&require=Core%2FSlick.Parser&require=Core%2FArray&require=Core%2FEvent&require=Core%2FFunction&require=Core%2FNumber&require=Core%2FObject&require=Core%2FString&require=Core%2FCookie&require=Core%2FDOMReady&require=Core%2FJSON&require=Core%2FSwiff&require=Clientcide%2FBehavior.StickyWin&require=Clientcide%2FCollapsible&require=Clientcide%2FMultipleOpenAccordion&require=Clientcide%2FTabSwapper&require=Clientcide%2FStickyWin.Ajax&require=Clientcide%2FStickyWin.Alert&require=Clientcide%2FStickyWin.Confirm&require=Clientcide%2FStickyWin.Drag&require=Clientcide%2FStickyWin.Fx&require=Clientcide%2FStickyWin.Modal&require=Clientcide%2FStickyWin.UI&require=More%2FElement.Forms&require=More%2FOverText&require=More%2FFx.Accordion&require=More%2FFx.Move&require=More%2FFx.Reveal&require=More%2FFx.Scroll&require=More%2FFx.Slide&require=More%2FKeyboard.Extras&require=More%2FSpinner&require=More%2FMore&require=More%2FRequest.JSONP&require=More%2FRequest.Periodical&require=More%2FArray.Extras&require=More%2FDate.Extras&require=More%2FNumber.Format&require=More%2FURI.Relative&require=More%2FAssets&require=More%2FColor&require=More%2FHash.Cookie
3 //Contents: Core:Source/Core/Core.js, Core:Source/Types/Object.js, Core:Source/Types/Array.js, Core:Source/Types/Function.js, Core:Source/Types/Number.js, Core:Source/Types/String.js, Core:Source/Browser/Browser.js, Core:Source/Slick/Slick.Parser.js, Core:Source/Slick/Slick.Finder.js, Core:Source/Element/Element.js, Core:Source/Class/Class.js, Core:Source/Class/Class.Extras.js, Core:Source/Request/Request.js, Core:Source/Utilities/JSON.js, Core:Source/Request/Request.JSON.js, Core:Source/Types/DOMEvent.js, Core:Source/Element/Element.Event.js, Core:Source/Element/Element.Delegation.js, Core:Source/Fx/Fx.js, Core:Source/Element/Element.Style.js, Core:Source/Fx/Fx.CSS.js, Core:Source/Fx/Fx.Morph.js, Core:Source/Utilities/Swiff.js, Core:Source/Fx/Fx.Transitions.js, More:Source/More/More.js, More:Source/Class/Class.Binds.js, More:Source/Class/Class.Occlude.js, Core:Source/Element/Element.Dimensions.js, More:Source/Element/Element.Measure.js, More:Source/Element/Element.Position.js, More:Source/Element/Element.Shortcuts.js, More:Source/Forms/OverText.js, More:Source/Utilities/IframeShim.js, More:Source/Interface/Mask.js, Core:Source/Utilities/DOMReady.js, More:Source/Element/Element.Pin.js, More:Source/Types/Object.Extras.js, Clientcide:Source/Core/Clientcide.js, Clientcide:Source/Core/dbug.js, Clientcide:Source/UI/StyleWriter.js, Clientcide:Source/UI/StickyWin.js, Clientcide:Source/UI/StickyWin.Modal.js, More:Source/Types/String.Extras.js, Clientcide:Source/UI/StickyWin.UI.js, Clientcide:Source/UI/StickyWin.Alert.js, Clientcide:Source/UI/StickyWin.Confirm.js, More:Source/Fx/Fx.Move.js, More:Source/Fx/Fx.Scroll.js, More:Source/Class/Class.Refactor.js, Core:Source/Fx/Fx.Tween.js, Clientcide:Source/UI/StickyWin.Fx.js, More:Source/Types/Array.Extras.js, Core:Source/Request/Request.HTML.js, Clientcide:Source/Layout/TabSwapper.js, More:Source/Element/Element.Forms.js, More:Source/Fx/Fx.Reveal.js, Clientcide:Source/Layout/Collapsible.js, More:Source/Utilities/Table.js, Behavior:Source/Element.Data.js, Behavior:Source/BehaviorAPI.js, Behavior:Source/Behavior.js, More:Source/Drag/Drag.js, More:Source/Drag/Drag.Move.js, Clientcide:Source/UI/StickyWin.Drag.js, Clientcide:Source/Behaviors/Behavior.StickyWin.js, More:Source/Utilities/Color.js, More:Source/Class/Events.Pseudos.js, More:Source/Element/Element.Event.Pseudos.js, More:Source/Element/Element.Event.Pseudos.Keys.js, More:Source/Interface/Keyboard.js, More:Source/Interface/Keyboard.Extras.js, More:Source/Locale/Locale.js, More:Source/Locale/Locale.en-US.Number.js, More:Source/Types/Number.Format.js, More:Source/Request/Request.Periodical.js, More:Source/Request/Request.JSONP.js, More:Source/Types/String.QueryString.js, More:Source/Types/URI.js, More:Source/Types/URI.Relative.js, Core:Source/Utilities/Cookie.js, More:Source/Locale/Locale.en-US.Date.js, More:Source/Types/Date.js, More:Source/Types/Date.Extras.js, More:Source/Fx/Fx.Elements.js, More:Source/Fx/Fx.Accordion.js, More:Source/Types/Hash.js, More:Source/Utilities/Hash.Cookie.js, More:Source/Utilities/Assets.js, More:Source/Interface/Spinner.js, More:Source/Fx/Fx.Slide.js, Clientcide:Source/UI/StickyWin.UI.Pointy.js, Clientcide:Source/UI/StickyWin.PointyTip.js, Clientcide:Source/UI/StickyWin.Ajax.js, Clientcide:Source/Layout/MultipleOpenAccordion.js
4
5 // Begin: Source/Core/Core.js
6 /*
7 ---
8
9 name: Core
10
11 description: The heart of MooTools.
12
13 license: MIT-style license.
14
15 copyright: Copyright (c) 2006-2012 [Valerio Proietti](http://mad4milk.net/).
16
17 authors: The MooTools production team (http://mootools.net/developers/)
18
19 inspiration:
20   - Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)
21   - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
22
23 provides: [Core, MooTools, Type, typeOf, instanceOf, Native]
24
25 ...
26 */
27
28 (function(){
29
30 this.MooTools = {
31         version: '1.4.5',
32         build: 'ab8ea8824dc3b24b6666867a2c4ed58ebb762cf0'
33 };
34
35 // typeOf, instanceOf
36
37 var typeOf = this.typeOf = function(item){
38         if (item == null) return 'null';
39         if (item.$family != null) return item.$family();
40
41         if (item.nodeName){
42                 if (item.nodeType == 1) return 'element';
43                 if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace';
44         } else if (typeof item.length == 'number'){
45                 if (item.callee) return 'arguments';
46                 if ('item' in item) return 'collection';
47         }
48
49         return typeof item;
50 };
51
52 var instanceOf = this.instanceOf = function(item, object){
53         if (item == null) return false;
54         var constructor = item.$constructor || item.constructor;
55         while (constructor){
56                 if (constructor === object) return true;
57                 constructor = constructor.parent;
58         }
59         /*<ltIE8>*/
60         if (!item.hasOwnProperty) return false;
61         /*</ltIE8>*/
62         return item instanceof object;
63 };
64
65 // Function overloading
66
67 var Function = this.Function;
68
69 var enumerables = true;
70 for (var i in {toString: 1}) enumerables = null;
71 if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor'];
72
73 Function.prototype.overloadSetter = function(usePlural){
74         var self = this;
75         return function(a, b){
76                 if (a == null) return this;
77                 if (usePlural || typeof a != 'string'){
78                         for (var k in a) self.call(this, k, a[k]);
79                         if (enumerables) for (var i = enumerables.length; i--;){
80                                 k = enumerables[i];
81                                 if (a.hasOwnProperty(k)) self.call(this, k, a[k]);
82                         }
83                 } else {
84                         self.call(this, a, b);
85                 }
86                 return this;
87         };
88 };
89
90 Function.prototype.overloadGetter = function(usePlural){
91         var self = this;
92         return function(a){
93                 var args, result;
94                 if (typeof a != 'string') args = a;
95                 else if (arguments.length > 1) args = arguments;
96                 else if (usePlural) args = [a];
97                 if (args){
98                         result = {};
99                         for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]);
100                 } else {
101                         result = self.call(this, a);
102                 }
103                 return result;
104         };
105 };
106
107 Function.prototype.extend = function(key, value){
108         this[key] = value;
109 }.overloadSetter();
110
111 Function.prototype.implement = function(key, value){
112         this.prototype[key] = value;
113 }.overloadSetter();
114
115 // From
116
117 var slice = Array.prototype.slice;
118
119 Function.from = function(item){
120         return (typeOf(item) == 'function') ? item : function(){
121                 return item;
122         };
123 };
124
125 Array.from = function(item){
126         if (item == null) return [];
127         return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) == 'array') ? item : slice.call(item) : [item];
128 };
129
130 Number.from = function(item){
131         var number = parseFloat(item);
132         return isFinite(number) ? number : null;
133 };
134
135 String.from = function(item){
136         return item + '';
137 };
138
139 // hide, protect
140
141 Function.implement({
142
143         hide: function(){
144                 this.$hidden = true;
145                 return this;
146         },
147
148         protect: function(){
149                 this.$protected = true;
150                 return this;
151         }
152
153 });
154
155 // Type
156
157 var Type = this.Type = function(name, object){
158         if (name){
159                 var lower = name.toLowerCase();
160                 var typeCheck = function(item){
161                         return (typeOf(item) == lower);
162                 };
163
164                 Type['is' + name] = typeCheck;
165                 if (object != null){
166                         object.prototype.$family = (function(){
167                                 return lower;
168                         }).hide();
169                         //<1.2compat>
170                         object.type = typeCheck;
171                         //</1.2compat>
172                 }
173         }
174
175         if (object == null) return null;
176
177         object.extend(this);
178         object.$constructor = Type;
179         object.prototype.$constructor = object;
180
181         return object;
182 };
183
184 var toString = Object.prototype.toString;
185
186 Type.isEnumerable = function(item){
187         return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' );
188 };
189
190 var hooks = {};
191
192 var hooksOf = function(object){
193         var type = typeOf(object.prototype);
194         return hooks[type] || (hooks[type] = []);
195 };
196
197 var implement = function(name, method){
198         if (method && method.$hidden) return;
199
200         var hooks = hooksOf(this);
201
202         for (var i = 0; i < hooks.length; i++){
203                 var hook = hooks[i];
204                 if (typeOf(hook) == 'type') implement.call(hook, name, method);
205                 else hook.call(this, name, method);
206         }
207
208         var previous = this.prototype[name];
209         if (previous == null || !previous.$protected) this.prototype[name] = method;
210
211         if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){
212                 return method.apply(item, slice.call(arguments, 1));
213         });
214 };
215
216 var extend = function(name, method){
217         if (method && method.$hidden) return;
218         var previous = this[name];
219         if (previous == null || !previous.$protected) this[name] = method;
220 };
221
222 Type.implement({
223
224         implement: implement.overloadSetter(),
225
226         extend: extend.overloadSetter(),
227
228         alias: function(name, existing){
229                 implement.call(this, name, this.prototype[existing]);
230         }.overloadSetter(),
231
232         mirror: function(hook){
233                 hooksOf(this).push(hook);
234                 return this;
235         }
236
237 });
238
239 new Type('Type', Type);
240
241 // Default Types
242
243 var force = function(name, object, methods){
244         var isType = (object != Object),
245                 prototype = object.prototype;
246
247         if (isType) object = new Type(name, object);
248
249         for (var i = 0, l = methods.length; i < l; i++){
250                 var key = methods[i],
251                         generic = object[key],
252                         proto = prototype[key];
253
254                 if (generic) generic.protect();
255                 if (isType && proto) object.implement(key, proto.protect());
256         }
257
258         if (isType){
259                 var methodsEnumerable = prototype.propertyIsEnumerable(methods[0]);
260                 object.forEachMethod = function(fn){
261                         if (!methodsEnumerable) for (var i = 0, l = methods.length; i < l; i++){
262                                 fn.call(prototype, prototype[methods[i]], methods[i]);
263                         }
264                         for (var key in prototype) fn.call(prototype, prototype[key], key)
265                 };
266         }
267
268         return force;
269 };
270
271 force('String', String, [
272         'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search',
273         'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase'
274 ])('Array', Array, [
275         'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice',
276         'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight'
277 ])('Number', Number, [
278         'toExponential', 'toFixed', 'toLocaleString', 'toPrecision'
279 ])('Function', Function, [
280         'apply', 'call', 'bind'
281 ])('RegExp', RegExp, [
282         'exec', 'test'
283 ])('Object', Object, [
284         'create', 'defineProperty', 'defineProperties', 'keys',
285         'getPrototypeOf', 'getOwnPropertyDescriptor', 'getOwnPropertyNames',
286         'preventExtensions', 'isExtensible', 'seal', 'isSealed', 'freeze', 'isFrozen'
287 ])('Date', Date, ['now']);
288
289 Object.extend = extend.overloadSetter();
290
291 Date.extend('now', function(){
292         return +(new Date);
293 });
294
295 new Type('Boolean', Boolean);
296
297 // fixes NaN returning as Number
298
299 Number.prototype.$family = function(){
300         return isFinite(this) ? 'number' : 'null';
301 }.hide();
302
303 // Number.random
304
305 Number.extend('random', function(min, max){
306         return Math.floor(Math.random() * (max - min + 1) + min);
307 });
308
309 // forEach, each
310
311 var hasOwnProperty = Object.prototype.hasOwnProperty;
312 Object.extend('forEach', function(object, fn, bind){
313         for (var key in object){
314                 if (hasOwnProperty.call(object, key)) fn.call(bind, object[key], key, object);
315         }
316 });
317
318 Object.each = Object.forEach;
319
320 Array.implement({
321
322         forEach: function(fn, bind){
323                 for (var i = 0, l = this.length; i < l; i++){
324                         if (i in this) fn.call(bind, this[i], i, this);
325                 }
326         },
327
328         each: function(fn, bind){
329                 Array.forEach(this, fn, bind);
330                 return this;
331         }
332
333 });
334
335 // Array & Object cloning, Object merging and appending
336
337 var cloneOf = function(item){
338         switch (typeOf(item)){
339                 case 'array': return item.clone();
340                 case 'object': return Object.clone(item);
341                 default: return item;
342         }
343 };
344
345 Array.implement('clone', function(){
346         var i = this.length, clone = new Array(i);
347         while (i--) clone[i] = cloneOf(this[i]);
348         return clone;
349 });
350
351 var mergeOne = function(source, key, current){
352         switch (typeOf(current)){
353                 case 'object':
354                         if (typeOf(source[key]) == 'object') Object.merge(source[key], current);
355                         else source[key] = Object.clone(current);
356                 break;
357                 case 'array': source[key] = current.clone(); break;
358                 default: source[key] = current;
359         }
360         return source;
361 };
362
363 Object.extend({
364
365         merge: function(source, k, v){
366                 if (typeOf(k) == 'string') return mergeOne(source, k, v);
367                 for (var i = 1, l = arguments.length; i < l; i++){
368                         var object = arguments[i];
369                         for (var key in object) mergeOne(source, key, object[key]);
370                 }
371                 return source;
372         },
373
374         clone: function(object){
375                 var clone = {};
376                 for (var key in object) clone[key] = cloneOf(object[key]);
377                 return clone;
378         },
379
380         append: function(original){
381                 for (var i = 1, l = arguments.length; i < l; i++){
382                         var extended = arguments[i] || {};
383                         for (var key in extended) original[key] = extended[key];
384                 }
385                 return original;
386         }
387
388 });
389
390 // Object-less types
391
392 ['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){
393         new Type(name);
394 });
395
396 // Unique ID
397
398 var UID = Date.now();
399
400 String.extend('uniqueID', function(){
401         return (UID++).toString(36);
402 });
403
404 //<1.2compat>
405
406 var Hash = this.Hash = new Type('Hash', function(object){
407         if (typeOf(object) == 'hash') object = Object.clone(object.getClean());
408         for (var key in object) this[key] = object[key];
409         return this;
410 });
411
412 Hash.implement({
413
414         forEach: function(fn, bind){
415                 Object.forEach(this, fn, bind);
416         },
417
418         getClean: function(){
419                 var clean = {};
420                 for (var key in this){
421                         if (this.hasOwnProperty(key)) clean[key] = this[key];
422                 }
423                 return clean;
424         },
425
426         getLength: function(){
427                 var length = 0;
428                 for (var key in this){
429                         if (this.hasOwnProperty(key)) length++;
430                 }
431                 return length;
432         }
433
434 });
435
436 Hash.alias('each', 'forEach');
437
438 Object.type = Type.isObject;
439
440 var Native = this.Native = function(properties){
441         return new Type(properties.name, properties.initialize);
442 };
443
444 Native.type = Type.type;
445
446 Native.implement = function(objects, methods){
447         for (var i = 0; i < objects.length; i++) objects[i].implement(methods);
448         return Native;
449 };
450
451 var arrayType = Array.type;
452 Array.type = function(item){
453         return instanceOf(item, Array) || arrayType(item);
454 };
455
456 this.$A = function(item){
457         return Array.from(item).slice();
458 };
459
460 this.$arguments = function(i){
461         return function(){
462                 return arguments[i];
463         };
464 };
465
466 this.$chk = function(obj){
467         return !!(obj || obj === 0);
468 };
469
470 this.$clear = function(timer){
471         clearTimeout(timer);
472         clearInterval(timer);
473         return null;
474 };
475
476 this.$defined = function(obj){
477         return (obj != null);
478 };
479
480 this.$each = function(iterable, fn, bind){
481         var type = typeOf(iterable);
482         ((type == 'arguments' || type == 'collection' || type == 'array' || type == 'elements') ? Array : Object).each(iterable, fn, bind);
483 };
484
485 this.$empty = function(){};
486
487 this.$extend = function(original, extended){
488         return Object.append(original, extended);
489 };
490
491 this.$H = function(object){
492         return new Hash(object);
493 };
494
495 this.$merge = function(){
496         var args = Array.slice(arguments);
497         args.unshift({});
498         return Object.merge.apply(null, args);
499 };
500
501 this.$lambda = Function.from;
502 this.$mixin = Object.merge;
503 this.$random = Number.random;
504 this.$splat = Array.from;
505 this.$time = Date.now;
506
507 this.$type = function(object){
508         var type = typeOf(object);
509         if (type == 'elements') return 'array';
510         return (type == 'null') ? false : type;
511 };
512
513 this.$unlink = function(object){
514         switch (typeOf(object)){
515                 case 'object': return Object.clone(object);
516                 case 'array': return Array.clone(object);
517                 case 'hash': return new Hash(object);
518                 default: return object;
519         }
520 };
521
522 //</1.2compat>
523
524 })();
525
526
527 // Begin: Source/Types/Object.js
528 /*
529 ---
530
531 name: Object
532
533 description: Object generic methods
534
535 license: MIT-style license.
536
537 requires: Type
538
539 provides: [Object, Hash]
540
541 ...
542 */
543
544 (function(){
545
546 var hasOwnProperty = Object.prototype.hasOwnProperty;
547
548 Object.extend({
549
550         subset: function(object, keys){
551                 var results = {};
552                 for (var i = 0, l = keys.length; i < l; i++){
553                         var k = keys[i];
554                         if (k in object) results[k] = object[k];
555                 }
556                 return results;
557         },
558
559         map: function(object, fn, bind){
560                 var results = {};
561                 for (var key in object){
562                         if (hasOwnProperty.call(object, key)) results[key] = fn.call(bind, object[key], key, object);
563                 }
564                 return results;
565         },
566
567         filter: function(object, fn, bind){
568                 var results = {};
569                 for (var key in object){
570                         var value = object[key];
571                         if (hasOwnProperty.call(object, key) && fn.call(bind, value, key, object)) results[key] = value;
572                 }
573                 return results;
574         },
575
576         every: function(object, fn, bind){
577                 for (var key in object){
578                         if (hasOwnProperty.call(object, key) && !fn.call(bind, object[key], key)) return false;
579                 }
580                 return true;
581         },
582
583         some: function(object, fn, bind){
584                 for (var key in object){
585                         if (hasOwnProperty.call(object, key) && fn.call(bind, object[key], key)) return true;
586                 }
587                 return false;
588         },
589
590         keys: function(object){
591                 var keys = [];
592                 for (var key in object){
593                         if (hasOwnProperty.call(object, key)) keys.push(key);
594                 }
595                 return keys;
596         },
597
598         values: function(object){
599                 var values = [];
600                 for (var key in object){
601                         if (hasOwnProperty.call(object, key)) values.push(object[key]);
602                 }
603                 return values;
604         },
605
606         getLength: function(object){
607                 return Object.keys(object).length;
608         },
609
610         keyOf: function(object, value){
611                 for (var key in object){
612                         if (hasOwnProperty.call(object, key) && object[key] === value) return key;
613                 }
614                 return null;
615         },
616
617         contains: function(object, value){
618                 return Object.keyOf(object, value) != null;
619         },
620
621         toQueryString: function(object, base){
622                 var queryString = [];
623
624                 Object.each(object, function(value, key){
625                         if (base) key = base + '[' + key + ']';
626                         var result;
627                         switch (typeOf(value)){
628                                 case 'object': result = Object.toQueryString(value, key); break;
629                                 case 'array':
630                                         var qs = {};
631                                         value.each(function(val, i){
632                                                 qs[i] = val;
633                                         });
634                                         result = Object.toQueryString(qs, key);
635                                 break;
636                                 default: result = key + '=' + encodeURIComponent(value);
637                         }
638                         if (value != null) queryString.push(result);
639                 });
640
641                 return queryString.join('&');
642         }
643
644 });
645
646 })();
647
648 //<1.2compat>
649
650 Hash.implement({
651
652         has: Object.prototype.hasOwnProperty,
653
654         keyOf: function(value){
655                 return Object.keyOf(this, value);
656         },
657
658         hasValue: function(value){
659                 return Object.contains(this, value);
660         },
661
662         extend: function(properties){
663                 Hash.each(properties || {}, function(value, key){
664                         Hash.set(this, key, value);
665                 }, this);
666                 return this;
667         },
668
669         combine: function(properties){
670                 Hash.each(properties || {}, function(value, key){
671                         Hash.include(this, key, value);
672                 }, this);
673                 return this;
674         },
675
676         erase: function(key){
677                 if (this.hasOwnProperty(key)) delete this[key];
678                 return this;
679         },
680
681         get: function(key){
682                 return (this.hasOwnProperty(key)) ? this[key] : null;
683         },
684
685         set: function(key, value){
686                 if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
687                 return this;
688         },
689
690         empty: function(){
691                 Hash.each(this, function(value, key){
692                         delete this[key];
693                 }, this);
694                 return this;
695         },
696
697         include: function(key, value){
698                 if (this[key] == null) this[key] = value;
699                 return this;
700         },
701
702         map: function(fn, bind){
703                 return new Hash(Object.map(this, fn, bind));
704         },
705
706         filter: function(fn, bind){
707                 return new Hash(Object.filter(this, fn, bind));
708         },
709
710         every: function(fn, bind){
711                 return Object.every(this, fn, bind);
712         },
713
714         some: function(fn, bind){
715                 return Object.some(this, fn, bind);
716         },
717
718         getKeys: function(){
719                 return Object.keys(this);
720         },
721
722         getValues: function(){
723                 return Object.values(this);
724         },
725
726         toQueryString: function(base){
727                 return Object.toQueryString(this, base);
728         }
729
730 });
731
732 Hash.extend = Object.append;
733
734 Hash.alias({indexOf: 'keyOf', contains: 'hasValue'});
735
736 //</1.2compat>
737
738
739 // Begin: Source/Types/Array.js
740 /*
741 ---
742
743 name: Array
744
745 description: Contains Array Prototypes like each, contains, and erase.
746
747 license: MIT-style license.
748
749 requires: Type
750
751 provides: Array
752
753 ...
754 */
755
756 Array.implement({
757
758         /*<!ES5>*/
759         every: function(fn, bind){
760                 for (var i = 0, l = this.length >>> 0; i < l; i++){
761                         if ((i in this) && !fn.call(bind, this[i], i, this)) return false;
762                 }
763                 return true;
764         },
765
766         filter: function(fn, bind){
767                 var results = [];
768                 for (var value, i = 0, l = this.length >>> 0; i < l; i++) if (i in this){
769                         value = this[i];
770                         if (fn.call(bind, value, i, this)) results.push(value);
771                 }
772                 return results;
773         },
774
775         indexOf: function(item, from){
776                 var length = this.length >>> 0;
777                 for (var i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++){
778                         if (this[i] === item) return i;
779                 }
780                 return -1;
781         },
782
783         map: function(fn, bind){
784                 var length = this.length >>> 0, results = Array(length);
785                 for (var i = 0; i < length; i++){
786                         if (i in this) results[i] = fn.call(bind, this[i], i, this);
787                 }
788                 return results;
789         },
790
791         some: function(fn, bind){
792                 for (var i = 0, l = this.length >>> 0; i < l; i++){
793                         if ((i in this) && fn.call(bind, this[i], i, this)) return true;
794                 }
795                 return false;
796         },
797         /*</!ES5>*/
798
799         clean: function(){
800                 return this.filter(function(item){
801                         return item != null;
802                 });
803         },
804
805         invoke: function(methodName){
806                 var args = Array.slice(arguments, 1);
807                 return this.map(function(item){
808                         return item[methodName].apply(item, args);
809                 });
810         },
811
812         associate: function(keys){
813                 var obj = {}, length = Math.min(this.length, keys.length);
814                 for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
815                 return obj;
816         },
817
818         link: function(object){
819                 var result = {};
820                 for (var i = 0, l = this.length; i < l; i++){
821                         for (var key in object){
822                                 if (object[key](this[i])){
823                                         result[key] = this[i];
824                                         delete object[key];
825                                         break;
826                                 }
827                         }
828                 }
829                 return result;
830         },
831
832         contains: function(item, from){
833                 return this.indexOf(item, from) != -1;
834         },
835
836         append: function(array){
837                 this.push.apply(this, array);
838                 return this;
839         },
840
841         getLast: function(){
842                 return (this.length) ? this[this.length - 1] : null;
843         },
844
845         getRandom: function(){
846                 return (this.length) ? this[Number.random(0, this.length - 1)] : null;
847         },
848
849         include: function(item){
850                 if (!this.contains(item)) this.push(item);
851                 return this;
852         },
853
854         combine: function(array){
855                 for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
856                 return this;
857         },
858
859         erase: function(item){
860                 for (var i = this.length; i--;){
861                         if (this[i] === item) this.splice(i, 1);
862                 }
863                 return this;
864         },
865
866         empty: function(){
867                 this.length = 0;
868                 return this;
869         },
870
871         flatten: function(){
872                 var array = [];
873                 for (var i = 0, l = this.length; i < l; i++){
874                         var type = typeOf(this[i]);
875                         if (type == 'null') continue;
876                         array = array.concat((type == 'array' || type == 'collection' || type == 'arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]);
877                 }
878                 return array;
879         },
880
881         pick: function(){
882                 for (var i = 0, l = this.length; i < l; i++){
883                         if (this[i] != null) return this[i];
884                 }
885                 return null;
886         },
887
888         hexToRgb: function(array){
889                 if (this.length != 3) return null;
890                 var rgb = this.map(function(value){
891                         if (value.length == 1) value += value;
892                         return value.toInt(16);
893                 });
894                 return (array) ? rgb : 'rgb(' + rgb + ')';
895         },
896
897         rgbToHex: function(array){
898                 if (this.length < 3) return null;
899                 if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
900                 var hex = [];
901                 for (var i = 0; i < 3; i++){
902                         var bit = (this[i] - 0).toString(16);
903                         hex.push((bit.length == 1) ? '0' + bit : bit);
904                 }
905                 return (array) ? hex : '#' + hex.join('');
906         }
907
908 });
909
910 //<1.2compat>
911
912 Array.alias('extend', 'append');
913
914 var $pick = function(){
915         return Array.from(arguments).pick();
916 };
917
918 //</1.2compat>
919
920
921 // Begin: Source/Types/Function.js
922 /*
923 ---
924
925 name: Function
926
927 description: Contains Function Prototypes like create, bind, pass, and delay.
928
929 license: MIT-style license.
930
931 requires: Type
932
933 provides: Function
934
935 ...
936 */
937
938 Function.extend({
939
940         attempt: function(){
941                 for (var i = 0, l = arguments.length; i < l; i++){
942                         try {
943                                 return arguments[i]();
944                         } catch (e){}
945                 }
946                 return null;
947         }
948
949 });
950
951 Function.implement({
952
953         attempt: function(args, bind){
954                 try {
955                         return this.apply(bind, Array.from(args));
956                 } catch (e){}
957
958                 return null;
959         },
960
961         /*<!ES5-bind>*/
962         bind: function(that){
963                 var self = this,
964                         args = arguments.length > 1 ? Array.slice(arguments, 1) : null,
965                         F = function(){};
966
967                 var bound = function(){
968                         var context = that, length = arguments.length;
969                         if (this instanceof bound){
970                                 F.prototype = self.prototype;
971                                 context = new F;
972                         }
973                         var result = (!args && !length)
974                                 ? self.call(context)
975                                 : self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments);
976                         return context == that ? result : context;
977                 };
978                 return bound;
979         },
980         /*</!ES5-bind>*/
981
982         pass: function(args, bind){
983                 var self = this;
984                 if (args != null) args = Array.from(args);
985                 return function(){
986                         return self.apply(bind, args || arguments);
987                 };
988         },
989
990         delay: function(delay, bind, args){
991                 return setTimeout(this.pass((args == null ? [] : args), bind), delay);
992         },
993
994         periodical: function(periodical, bind, args){
995                 return setInterval(this.pass((args == null ? [] : args), bind), periodical);
996         }
997
998 });
999
1000 //<1.2compat>
1001
1002 delete Function.prototype.bind;
1003
1004 Function.implement({
1005
1006         create: function(options){
1007                 var self = this;
1008                 options = options || {};
1009                 return function(event){
1010                         var args = options.arguments;
1011                         args = (args != null) ? Array.from(args) : Array.slice(arguments, (options.event) ? 1 : 0);
1012                         if (options.event) args = [event || window.event].extend(args);
1013                         var returns = function(){
1014                                 return self.apply(options.bind || null, args);
1015                         };
1016                         if (options.delay) return setTimeout(returns, options.delay);
1017                         if (options.periodical) return setInterval(returns, options.periodical);
1018                         if (options.attempt) return Function.attempt(returns);
1019                         return returns();
1020                 };
1021         },
1022
1023         bind: function(bind, args){
1024                 var self = this;
1025                 if (args != null) args = Array.from(args);
1026                 return function(){
1027                         return self.apply(bind, args || arguments);
1028                 };
1029         },
1030
1031         bindWithEvent: function(bind, args){
1032                 var self = this;
1033                 if (args != null) args = Array.from(args);
1034                 return function(event){
1035                         return self.apply(bind, (args == null) ? arguments : [event].concat(args));
1036                 };
1037         },
1038
1039         run: function(args, bind){
1040                 return this.apply(bind, Array.from(args));
1041         }
1042
1043 });
1044
1045 if (Object.create == Function.prototype.create) Object.create = null;
1046
1047 var $try = Function.attempt;
1048
1049 //</1.2compat>
1050
1051
1052 // Begin: Source/Types/Number.js
1053 /*
1054 ---
1055
1056 name: Number
1057
1058 description: Contains Number Prototypes like limit, round, times, and ceil.
1059
1060 license: MIT-style license.
1061
1062 requires: Type
1063
1064 provides: Number
1065
1066 ...
1067 */
1068
1069 Number.implement({
1070
1071         limit: function(min, max){
1072                 return Math.min(max, Math.max(min, this));
1073         },
1074
1075         round: function(precision){
1076                 precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0);
1077                 return Math.round(this * precision) / precision;
1078         },
1079
1080         times: function(fn, bind){
1081                 for (var i = 0; i < this; i++) fn.call(bind, i, this);
1082         },
1083
1084         toFloat: function(){
1085                 return parseFloat(this);
1086         },
1087
1088         toInt: function(base){
1089                 return parseInt(this, base || 10);
1090         }
1091
1092 });
1093
1094 Number.alias('each', 'times');
1095
1096 (function(math){
1097         var methods = {};
1098         math.each(function(name){
1099                 if (!Number[name]) methods[name] = function(){
1100                         return Math[name].apply(null, [this].concat(Array.from(arguments)));
1101                 };
1102         });
1103         Number.implement(methods);
1104 })(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
1105
1106
1107 // Begin: Source/Types/String.js
1108 /*
1109 ---
1110
1111 name: String
1112
1113 description: Contains String Prototypes like camelCase, capitalize, test, and toInt.
1114
1115 license: MIT-style license.
1116
1117 requires: Type
1118
1119 provides: String
1120
1121 ...
1122 */
1123
1124 String.implement({
1125
1126         test: function(regex, params){
1127                 return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this);
1128         },
1129
1130         contains: function(string, separator){
1131                 return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : String(this).indexOf(string) > -1;
1132         },
1133
1134         trim: function(){
1135                 return String(this).replace(/^\s+|\s+$/g, '');
1136         },
1137
1138         clean: function(){
1139                 return String(this).replace(/\s+/g, ' ').trim();
1140         },
1141
1142         camelCase: function(){
1143                 return String(this).replace(/-\D/g, function(match){
1144                         return match.charAt(1).toUpperCase();
1145                 });
1146         },
1147
1148         hyphenate: function(){
1149                 return String(this).replace(/[A-Z]/g, function(match){
1150                         return ('-' + match.charAt(0).toLowerCase());
1151                 });
1152         },
1153
1154         capitalize: function(){
1155                 return String(this).replace(/\b[a-z]/g, function(match){
1156                         return match.toUpperCase();
1157                 });
1158         },
1159
1160         escapeRegExp: function(){
1161                 return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
1162         },
1163
1164         toInt: function(base){
1165                 return parseInt(this, base || 10);
1166         },
1167
1168         toFloat: function(){
1169                 return parseFloat(this);
1170         },
1171
1172         hexToRgb: function(array){
1173                 var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
1174                 return (hex) ? hex.slice(1).hexToRgb(array) : null;
1175         },
1176
1177         rgbToHex: function(array){
1178                 var rgb = String(this).match(/\d{1,3}/g);
1179                 return (rgb) ? rgb.rgbToHex(array) : null;
1180         },
1181
1182         substitute: function(object, regexp){
1183                 return String(this).replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
1184                         if (match.charAt(0) == '\\') return match.slice(1);
1185                         return (object[name] != null) ? object[name] : '';
1186                 });
1187         }
1188
1189 });
1190
1191
1192 // Begin: Source/Browser/Browser.js
1193 /*
1194 ---
1195
1196 name: Browser
1197
1198 description: The Browser Object. Contains Browser initialization, Window and Document, and the Browser Hash.
1199
1200 license: MIT-style license.
1201
1202 requires: [Array, Function, Number, String]
1203
1204 provides: [Browser, Window, Document]
1205
1206 ...
1207 */
1208
1209 (function(){
1210
1211 var document = this.document;
1212 var window = document.window = this;
1213
1214 var ua = navigator.userAgent.toLowerCase(),
1215         platform = navigator.platform.toLowerCase(),
1216         UA = ua.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/) || [null, 'unknown', 0],
1217         mode = UA[1] == 'ie' && document.documentMode;
1218
1219 var Browser = this.Browser = {
1220
1221         extend: Function.prototype.extend,
1222
1223         name: (UA[1] == 'version') ? UA[3] : UA[1],
1224
1225         version: mode || parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]),
1226
1227         Platform: {
1228                 name: ua.match(/ip(?:ad|od|hone)/) ? 'ios' : (ua.match(/(?:webos|android)/) || platform.match(/mac|win|linux/) || ['other'])[0]
1229         },
1230
1231         Features: {
1232                 xpath: !!(document.evaluate),
1233                 air: !!(window.runtime),
1234                 query: !!(document.querySelector),
1235                 json: !!(window.JSON)
1236         },
1237
1238         Plugins: {}
1239
1240 };
1241
1242 Browser[Browser.name] = true;
1243 Browser[Browser.name + parseInt(Browser.version, 10)] = true;
1244 Browser.Platform[Browser.Platform.name] = true;
1245
1246 // Request
1247
1248 Browser.Request = (function(){
1249
1250         var XMLHTTP = function(){
1251                 return new XMLHttpRequest();
1252         };
1253
1254         var MSXML2 = function(){
1255                 return new ActiveXObject('MSXML2.XMLHTTP');
1256         };
1257
1258         var MSXML = function(){
1259                 return new ActiveXObject('Microsoft.XMLHTTP');
1260         };
1261
1262         return Function.attempt(function(){
1263                 XMLHTTP();
1264                 return XMLHTTP;
1265         }, function(){
1266                 MSXML2();
1267                 return MSXML2;
1268         }, function(){
1269                 MSXML();
1270                 return MSXML;
1271         });
1272
1273 })();
1274
1275 Browser.Features.xhr = !!(Browser.Request);
1276
1277 // Flash detection
1278
1279 var version = (Function.attempt(function(){
1280         return navigator.plugins['Shockwave Flash'].description;
1281 }, function(){
1282         return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
1283 }) || '0 r0').match(/\d+/g);
1284
1285 Browser.Plugins.Flash = {
1286         version: Number(version[0] || '0.' + version[1]) || 0,
1287         build: Number(version[2]) || 0
1288 };
1289
1290 // String scripts
1291
1292 Browser.exec = function(text){
1293         if (!text) return text;
1294         if (window.execScript){
1295                 window.execScript(text);
1296         } else {
1297                 var script = document.createElement('script');
1298                 script.setAttribute('type', 'text/javascript');
1299                 script.text = text;
1300                 document.head.appendChild(script);
1301                 document.head.removeChild(script);
1302         }
1303         return text;
1304 };
1305
1306 String.implement('stripScripts', function(exec){
1307         var scripts = '';
1308         var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(all, code){
1309                 scripts += code + '\n';
1310                 return '';
1311         });
1312         if (exec === true) Browser.exec(scripts);
1313         else if (typeOf(exec) == 'function') exec(scripts, text);
1314         return text;
1315 });
1316
1317 // Window, Document
1318
1319 Browser.extend({
1320         Document: this.Document,
1321         Window: this.Window,
1322         Element: this.Element,
1323         Event: this.Event
1324 });
1325
1326 this.Window = this.$constructor = new Type('Window', function(){});
1327
1328 this.$family = Function.from('window').hide();
1329
1330 Window.mirror(function(name, method){
1331         window[name] = method;
1332 });
1333
1334 this.Document = document.$constructor = new Type('Document', function(){});
1335
1336 document.$family = Function.from('document').hide();
1337
1338 Document.mirror(function(name, method){
1339         document[name] = method;
1340 });
1341
1342 document.html = document.documentElement;
1343 if (!document.head) document.head = document.getElementsByTagName('head')[0];
1344
1345 if (document.execCommand) try {
1346         document.execCommand("BackgroundImageCache", false, true);
1347 } catch (e){}
1348
1349 /*<ltIE9>*/
1350 if (this.attachEvent && !this.addEventListener){
1351         var unloadEvent = function(){
1352                 this.detachEvent('onunload', unloadEvent);
1353                 document.head = document.html = document.window = null;
1354         };
1355         this.attachEvent('onunload', unloadEvent);
1356 }
1357
1358 // IE fails on collections and <select>.options (refers to <select>)
1359 var arrayFrom = Array.from;
1360 try {
1361         arrayFrom(document.html.childNodes);
1362 } catch(e){
1363         Array.from = function(item){
1364                 if (typeof item != 'string' && Type.isEnumerable(item) && typeOf(item) != 'array'){
1365                         var i = item.length, array = new Array(i);
1366                         while (i--) array[i] = item[i];
1367                         return array;
1368                 }
1369                 return arrayFrom(item);
1370         };
1371
1372         var prototype = Array.prototype,
1373                 slice = prototype.slice;
1374         ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice'].each(function(name){
1375                 var method = prototype[name];
1376                 Array[name] = function(item){
1377                         return method.apply(Array.from(item), slice.call(arguments, 1));
1378                 };
1379         });
1380 }
1381 /*</ltIE9>*/
1382
1383 //<1.2compat>
1384
1385 if (Browser.Platform.ios) Browser.Platform.ipod = true;
1386
1387 Browser.Engine = {};
1388
1389 var setEngine = function(name, version){
1390         Browser.Engine.name = name;
1391         Browser.Engine[name + version] = true;
1392         Browser.Engine.version = version;
1393 };
1394
1395 if (Browser.ie){
1396         Browser.Engine.trident = true;
1397
1398         switch (Browser.version){
1399                 case 6: setEngine('trident', 4); break;
1400                 case 7: setEngine('trident', 5); break;
1401                 case 8: setEngine('trident', 6);
1402         }
1403 }
1404
1405 if (Browser.firefox){
1406         Browser.Engine.gecko = true;
1407
1408         if (Browser.version >= 3) setEngine('gecko', 19);
1409         else setEngine('gecko', 18);
1410 }
1411
1412 if (Browser.safari || Browser.chrome){
1413         Browser.Engine.webkit = true;
1414
1415         switch (Browser.version){
1416                 case 2: setEngine('webkit', 419); break;
1417                 case 3: setEngine('webkit', 420); break;
1418                 case 4: setEngine('webkit', 525);
1419         }
1420 }
1421
1422 if (Browser.opera){
1423         Browser.Engine.presto = true;
1424
1425         if (Browser.version >= 9.6) setEngine('presto', 960);
1426         else if (Browser.version >= 9.5) setEngine('presto', 950);
1427         else setEngine('presto', 925);
1428 }
1429
1430 if (Browser.name == 'unknown'){
1431         switch ((ua.match(/(?:webkit|khtml|gecko)/) || [])[0]){
1432                 case 'webkit':
1433                 case 'khtml':
1434                         Browser.Engine.webkit = true;
1435                 break;
1436                 case 'gecko':
1437                         Browser.Engine.gecko = true;
1438         }
1439 }
1440
1441 this.$exec = Browser.exec;
1442
1443 //</1.2compat>
1444
1445 })();
1446
1447
1448 // Begin: Source/Slick/Slick.Parser.js
1449 /*
1450 ---
1451 name: Slick.Parser
1452 description: Standalone CSS3 Selector parser
1453 provides: Slick.Parser
1454 ...
1455 */
1456
1457 ;(function(){
1458
1459 var parsed,
1460         separatorIndex,
1461         combinatorIndex,
1462         reversed,
1463         cache = {},
1464         reverseCache = {},
1465         reUnescape = /\\/g;
1466
1467 var parse = function(expression, isReversed){
1468         if (expression == null) return null;
1469         if (expression.Slick === true) return expression;
1470         expression = ('' + expression).replace(/^\s+|\s+$/g, '');
1471         reversed = !!isReversed;
1472         var currentCache = (reversed) ? reverseCache : cache;
1473         if (currentCache[expression]) return currentCache[expression];
1474         parsed = {
1475                 Slick: true,
1476                 expressions: [],
1477                 raw: expression,
1478                 reverse: function(){
1479                         return parse(this.raw, true);
1480                 }
1481         };
1482         separatorIndex = -1;
1483         while (expression != (expression = expression.replace(regexp, parser)));
1484         parsed.length = parsed.expressions.length;
1485         return currentCache[parsed.raw] = (reversed) ? reverse(parsed) : parsed;
1486 };
1487
1488 var reverseCombinator = function(combinator){
1489         if (combinator === '!') return ' ';
1490         else if (combinator === ' ') return '!';
1491         else if ((/^!/).test(combinator)) return combinator.replace(/^!/, '');
1492         else return '!' + combinator;
1493 };
1494
1495 var reverse = function(expression){
1496         var expressions = expression.expressions;
1497         for (var i = 0; i < expressions.length; i++){
1498                 var exp = expressions[i];
1499                 var last = {parts: [], tag: '*', combinator: reverseCombinator(exp[0].combinator)};
1500
1501                 for (var j = 0; j < exp.length; j++){
1502                         var cexp = exp[j];
1503                         if (!cexp.reverseCombinator) cexp.reverseCombinator = ' ';
1504                         cexp.combinator = cexp.reverseCombinator;
1505                         delete cexp.reverseCombinator;
1506                 }
1507
1508                 exp.reverse().push(last);
1509         }
1510         return expression;
1511 };
1512
1513 var escapeRegExp = function(string){// Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License
1514         return string.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, function(match){
1515                 return '\\' + match;
1516         });
1517 };
1518
1519 var regexp = new RegExp(
1520 /*
1521 #!/usr/bin/env ruby
1522 puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'')
1523 __END__
1524         "(?x)^(?:\
1525           \\s* ( , ) \\s*               # Separator          \n\
1526         | \\s* ( <combinator>+ ) \\s*   # Combinator         \n\
1527         |      ( \\s+ )                 # CombinatorChildren \n\
1528         |      ( <unicode>+ | \\* )     # Tag                \n\
1529         | \\#  ( <unicode>+       )     # ID                 \n\
1530         | \\.  ( <unicode>+       )     # ClassName          \n\
1531         |                               # Attribute          \n\
1532         \\[  \
1533                 \\s* (<unicode1>+)  (?:  \
1534                         \\s* ([*^$!~|]?=)  (?:  \
1535                                 \\s* (?:\
1536                                         ([\"']?)(.*?)\\9 \
1537                                 )\
1538                         )  \
1539                 )?  \\s*  \
1540         \\](?!\\]) \n\
1541         |   :+ ( <unicode>+ )(?:\
1542         \\( (?:\
1543                 (?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+)\
1544         ) \\)\
1545         )?\
1546         )"
1547 */
1548         "^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(<unicode>+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)"
1549         .replace(/<combinator>/, '[' + escapeRegExp(">+~`!@$%^&={}\\;</") + ']')
1550         .replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
1551         .replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
1552 );
1553
1554 function parser(
1555         rawMatch,
1556
1557         separator,
1558         combinator,
1559         combinatorChildren,
1560
1561         tagName,
1562         id,
1563         className,
1564
1565         attributeKey,
1566         attributeOperator,
1567         attributeQuote,
1568         attributeValue,
1569
1570         pseudoMarker,
1571         pseudoClass,
1572         pseudoQuote,
1573         pseudoClassQuotedValue,
1574         pseudoClassValue
1575 ){
1576         if (separator || separatorIndex === -1){
1577                 parsed.expressions[++separatorIndex] = [];
1578                 combinatorIndex = -1;
1579                 if (separator) return '';
1580         }
1581
1582         if (combinator || combinatorChildren || combinatorIndex === -1){
1583                 combinator = combinator || ' ';
1584                 var currentSeparator = parsed.expressions[separatorIndex];
1585                 if (reversed && currentSeparator[combinatorIndex])
1586                         currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(combinator);
1587                 currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*'};
1588         }
1589
1590         var currentParsed = parsed.expressions[separatorIndex][combinatorIndex];
1591
1592         if (tagName){
1593                 currentParsed.tag = tagName.replace(reUnescape, '');
1594
1595         } else if (id){
1596                 currentParsed.id = id.replace(reUnescape, '');
1597
1598         } else if (className){
1599                 className = className.replace(reUnescape, '');
1600
1601                 if (!currentParsed.classList) currentParsed.classList = [];
1602                 if (!currentParsed.classes) currentParsed.classes = [];
1603                 currentParsed.classList.push(className);
1604                 currentParsed.classes.push({
1605                         value: className,
1606                         regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)')
1607                 });
1608
1609         } else if (pseudoClass){
1610                 pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue;
1611                 pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '') : null;
1612
1613                 if (!currentParsed.pseudos) currentParsed.pseudos = [];
1614                 currentParsed.pseudos.push({
1615                         key: pseudoClass.replace(reUnescape, ''),
1616                         value: pseudoClassValue,
1617                         type: pseudoMarker.length == 1 ? 'class' : 'element'
1618                 });
1619
1620         } else if (attributeKey){
1621                 attributeKey = attributeKey.replace(reUnescape, '');
1622                 attributeValue = (attributeValue || '').replace(reUnescape, '');
1623
1624                 var test, regexp;
1625
1626                 switch (attributeOperator){
1627                         case '^=' : regexp = new RegExp(       '^'+ escapeRegExp(attributeValue)            ); break;
1628                         case '$=' : regexp = new RegExp(            escapeRegExp(attributeValue) +'$'       ); break;
1629                         case '~=' : regexp = new RegExp( '(^|\\s)'+ escapeRegExp(attributeValue) +'(\\s|$)' ); break;
1630                         case '|=' : regexp = new RegExp(       '^'+ escapeRegExp(attributeValue) +'(-|$)'   ); break;
1631                         case  '=' : test = function(value){
1632                                 return attributeValue == value;
1633                         }; break;
1634                         case '*=' : test = function(value){
1635                                 return value && value.indexOf(attributeValue) > -1;
1636                         }; break;
1637                         case '!=' : test = function(value){
1638                                 return attributeValue != value;
1639                         }; break;
1640                         default   : test = function(value){
1641                                 return !!value;
1642                         };
1643                 }
1644
1645                 if (attributeValue == '' && (/^[*$^]=$/).test(attributeOperator)) test = function(){
1646                         return false;
1647                 };
1648
1649                 if (!test) test = function(value){
1650                         return value && regexp.test(value);
1651                 };
1652
1653                 if (!currentParsed.attributes) currentParsed.attributes = [];
1654                 currentParsed.attributes.push({
1655                         key: attributeKey,
1656                         operator: attributeOperator,
1657                         value: attributeValue,
1658                         test: test
1659                 });
1660
1661         }
1662
1663         return '';
1664 };
1665
1666 // Slick NS
1667
1668 var Slick = (this.Slick || {});
1669
1670 Slick.parse = function(expression){
1671         return parse(expression);
1672 };
1673
1674 Slick.escapeRegExp = escapeRegExp;
1675
1676 if (!this.Slick) this.Slick = Slick;
1677
1678 }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);
1679
1680
1681 // Begin: Source/Slick/Slick.Finder.js
1682 /*
1683 ---
1684 name: Slick.Finder
1685 description: The new, superfast css selector engine.
1686 provides: Slick.Finder
1687 requires: Slick.Parser
1688 ...
1689 */
1690
1691 ;(function(){
1692
1693 var local = {},
1694         featuresCache = {},
1695         toString = Object.prototype.toString;
1696
1697 // Feature / Bug detection
1698
1699 local.isNativeCode = function(fn){
1700         return (/\{\s*\[native code\]\s*\}/).test('' + fn);
1701 };
1702
1703 local.isXML = function(document){
1704         return (!!document.xmlVersion) || (!!document.xml) || (toString.call(document) == '[object XMLDocument]') ||
1705         (document.nodeType == 9 && document.documentElement.nodeName != 'HTML');
1706 };
1707
1708 local.setDocument = function(document){
1709
1710         // convert elements / window arguments to document. if document cannot be extrapolated, the function returns.
1711         var nodeType = document.nodeType;
1712         if (nodeType == 9); // document
1713         else if (nodeType) document = document.ownerDocument; // node
1714         else if (document.navigator) document = document.document; // window
1715         else return;
1716
1717         // check if it's the old document
1718
1719         if (this.document === document) return;
1720         this.document = document;
1721
1722         // check if we have done feature detection on this document before
1723
1724         var root = document.documentElement,
1725                 rootUid = this.getUIDXML(root),
1726                 features = featuresCache[rootUid],
1727                 feature;
1728
1729         if (features){
1730                 for (feature in features){
1731                         this[feature] = features[feature];
1732                 }
1733                 return;
1734         }
1735
1736         features = featuresCache[rootUid] = {};
1737
1738         features.root = root;
1739         features.isXMLDocument = this.isXML(document);
1740
1741         features.brokenStarGEBTN
1742         = features.starSelectsClosedQSA
1743         = features.idGetsName
1744         = features.brokenMixedCaseQSA
1745         = features.brokenGEBCN
1746         = features.brokenCheckedQSA
1747         = features.brokenEmptyAttributeQSA
1748         = features.isHTMLDocument
1749         = features.nativeMatchesSelector
1750         = false;
1751
1752         var starSelectsClosed, starSelectsComments,
1753                 brokenSecondClassNameGEBCN, cachedGetElementsByClassName,
1754                 brokenFormAttributeGetter;
1755
1756         var selected, id = 'slick_uniqueid';
1757         var testNode = document.createElement('div');
1758
1759         var testRoot = document.body || document.getElementsByTagName('body')[0] || root;
1760         testRoot.appendChild(testNode);
1761
1762         // on non-HTML documents innerHTML and getElementsById doesnt work properly
1763         try {
1764                 testNode.innerHTML = '<a id="'+id+'"></a>';
1765                 features.isHTMLDocument = !!document.getElementById(id);
1766         } catch(e){};
1767
1768         if (features.isHTMLDocument){
1769
1770                 testNode.style.display = 'none';
1771
1772                 // IE returns comment nodes for getElementsByTagName('*') for some documents
1773                 testNode.appendChild(document.createComment(''));
1774                 starSelectsComments = (testNode.getElementsByTagName('*').length > 1);
1775
1776                 // IE returns closed nodes (EG:"</foo>") for getElementsByTagName('*') for some documents
1777                 try {
1778                         testNode.innerHTML = 'foo</foo>';
1779                         selected = testNode.getElementsByTagName('*');
1780                         starSelectsClosed = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/');
1781                 } catch(e){};
1782
1783                 features.brokenStarGEBTN = starSelectsComments || starSelectsClosed;
1784
1785                 // IE returns elements with the name instead of just id for getElementsById for some documents
1786                 try {
1787                         testNode.innerHTML = '<a name="'+ id +'"></a><b id="'+ id +'"></b>';
1788                         features.idGetsName = document.getElementById(id) === testNode.firstChild;
1789                 } catch(e){};
1790
1791                 if (testNode.getElementsByClassName){
1792
1793                         // Safari 3.2 getElementsByClassName caches results
1794                         try {
1795                                 testNode.innerHTML = '<a class="f"></a><a class="b"></a>';
1796                                 testNode.getElementsByClassName('b').length;
1797                                 testNode.firstChild.className = 'b';
1798                                 cachedGetElementsByClassName = (testNode.getElementsByClassName('b').length != 2);
1799                         } catch(e){};
1800
1801                         // Opera 9.6 getElementsByClassName doesnt detects the class if its not the first one
1802                         try {
1803                                 testNode.innerHTML = '<a class="a"></a><a class="f b a"></a>';
1804                                 brokenSecondClassNameGEBCN = (testNode.getElementsByClassName('a').length != 2);
1805                         } catch(e){};
1806
1807                         features.brokenGEBCN = cachedGetElementsByClassName || brokenSecondClassNameGEBCN;
1808                 }
1809
1810                 if (testNode.querySelectorAll){
1811                         // IE 8 returns closed nodes (EG:"</foo>") for querySelectorAll('*') for some documents
1812                         try {
1813                                 testNode.innerHTML = 'foo</foo>';
1814                                 selected = testNode.querySelectorAll('*');
1815                                 features.starSelectsClosedQSA = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/');
1816                         } catch(e){};
1817
1818                         // Safari 3.2 querySelectorAll doesnt work with mixedcase on quirksmode
1819                         try {
1820                                 testNode.innerHTML = '<a class="MiX"></a>';
1821                                 features.brokenMixedCaseQSA = !testNode.querySelectorAll('.MiX').length;
1822                         } catch(e){};
1823
1824                         // Webkit and Opera dont return selected options on querySelectorAll
1825                         try {
1826                                 testNode.innerHTML = '<select><option selected="selected">a</option></select>';
1827                                 features.brokenCheckedQSA = (testNode.querySelectorAll(':checked').length == 0);
1828                         } catch(e){};
1829
1830                         // IE returns incorrect results for attr[*^$]="" selectors on querySelectorAll
1831                         try {
1832                                 testNode.innerHTML = '<a class=""></a>';
1833                                 features.brokenEmptyAttributeQSA = (testNode.querySelectorAll('[class*=""]').length != 0);
1834                         } catch(e){};
1835
1836                 }
1837
1838                 // IE6-7, if a form has an input of id x, form.getAttribute(x) returns a reference to the input
1839                 try {
1840                         testNode.innerHTML = '<form action="s"><input id="action"/></form>';
1841                         brokenFormAttributeGetter = (testNode.firstChild.getAttribute('action') != 's');
1842                 } catch(e){};
1843
1844                 // native matchesSelector function
1845
1846                 features.nativeMatchesSelector = root.matchesSelector || /*root.msMatchesSelector ||*/ root.mozMatchesSelector || root.webkitMatchesSelector;
1847                 if (features.nativeMatchesSelector) try {
1848                         // if matchesSelector trows errors on incorrect sintaxes we can use it
1849                         features.nativeMatchesSelector.call(root, ':slick');
1850                         features.nativeMatchesSelector = null;
1851                 } catch(e){};
1852
1853         }
1854
1855         try {
1856                 root.slick_expando = 1;
1857                 delete root.slick_expando;
1858                 features.getUID = this.getUIDHTML;
1859         } catch(e) {
1860                 features.getUID = this.getUIDXML;
1861         }
1862
1863         testRoot.removeChild(testNode);
1864         testNode = selected = testRoot = null;
1865
1866         // getAttribute
1867
1868         features.getAttribute = (features.isHTMLDocument && brokenFormAttributeGetter) ? function(node, name){
1869                 var method = this.attributeGetters[name];
1870                 if (method) return method.call(node);
1871                 var attributeNode = node.getAttributeNode(name);
1872                 return (attributeNode) ? attributeNode.nodeValue : null;
1873         } : function(node, name){
1874                 var method = this.attributeGetters[name];
1875                 return (method) ? method.call(node) : node.getAttribute(name);
1876         };
1877
1878         // hasAttribute
1879
1880         features.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute) {
1881                 return node.hasAttribute(attribute);
1882         } : function(node, attribute) {
1883                 node = node.getAttributeNode(attribute);
1884                 return !!(node && (node.specified || node.nodeValue));
1885         };
1886
1887         // contains
1888         // FIXME: Add specs: local.contains should be different for xml and html documents?
1889         var nativeRootContains = root && this.isNativeCode(root.contains),
1890                 nativeDocumentContains = document && this.isNativeCode(document.contains);
1891
1892         features.contains = (nativeRootContains && nativeDocumentContains) ? function(context, node){
1893                 return context.contains(node);
1894         } : (nativeRootContains && !nativeDocumentContains) ? function(context, node){
1895                 // IE8 does not have .contains on document.
1896                 return context === node || ((context === document) ? document.documentElement : context).contains(node);
1897         } : (root && root.compareDocumentPosition) ? function(context, node){
1898                 return context === node || !!(context.compareDocumentPosition(node) & 16);
1899         } : function(context, node){
1900                 if (node) do {
1901                         if (node === context) return true;
1902                 } while ((node = node.parentNode));
1903                 return false;
1904         };
1905
1906         // document order sorting
1907         // credits to Sizzle (http://sizzlejs.com/)
1908
1909         features.documentSorter = (root.compareDocumentPosition) ? function(a, b){
1910                 if (!a.compareDocumentPosition || !b.compareDocumentPosition) return 0;
1911                 return a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
1912         } : ('sourceIndex' in root) ? function(a, b){
1913                 if (!a.sourceIndex || !b.sourceIndex) return 0;
1914                 return a.sourceIndex - b.sourceIndex;
1915         } : (document.createRange) ? function(a, b){
1916                 if (!a.ownerDocument || !b.ownerDocument) return 0;
1917                 var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
1918                 aRange.setStart(a, 0);
1919                 aRange.setEnd(a, 0);
1920                 bRange.setStart(b, 0);
1921                 bRange.setEnd(b, 0);
1922                 return aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
1923         } : null ;
1924
1925         root = null;
1926
1927         for (feature in features){
1928                 this[feature] = features[feature];
1929         }
1930 };
1931
1932 // Main Method
1933
1934 var reSimpleSelector = /^([#.]?)((?:[\w-]+|\*))$/,
1935         reEmptyAttribute = /\[.+[*$^]=(?:""|'')?\]/,
1936         qsaFailExpCache = {};
1937
1938 local.search = function(context, expression, append, first){
1939
1940         var found = this.found = (first) ? null : (append || []);
1941
1942         if (!context) return found;
1943         else if (context.navigator) context = context.document; // Convert the node from a window to a document
1944         else if (!context.nodeType) return found;
1945
1946         // setup
1947
1948         var parsed, i,
1949                 uniques = this.uniques = {},
1950                 hasOthers = !!(append && append.length),
1951                 contextIsDocument = (context.nodeType == 9);
1952
1953         if (this.document !== (contextIsDocument ? context : context.ownerDocument)) this.setDocument(context);
1954
1955         // avoid duplicating items already in the append array
1956         if (hasOthers) for (i = found.length; i--;) uniques[this.getUID(found[i])] = true;
1957
1958         // expression checks
1959
1960         if (typeof expression == 'string'){ // expression is a string
1961
1962                 /*<simple-selectors-override>*/
1963                 var simpleSelector = expression.match(reSimpleSelector);
1964                 simpleSelectors: if (simpleSelector) {
1965
1966                         var symbol = simpleSelector[1],
1967                                 name = simpleSelector[2],
1968                                 node, nodes;
1969
1970                         if (!symbol){
1971
1972                                 if (name == '*' && this.brokenStarGEBTN) break simpleSelectors;
1973                                 nodes = context.getElementsByTagName(name);
1974                                 if (first) return nodes[0] || null;
1975                                 for (i = 0; node = nodes[i++];){
1976                                         if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
1977                                 }
1978
1979                         } else if (symbol == '#'){
1980
1981                                 if (!this.isHTMLDocument || !contextIsDocument) break simpleSelectors;
1982                                 node = context.getElementById(name);
1983                                 if (!node) return found;
1984                                 if (this.idGetsName && node.getAttributeNode('id').nodeValue != name) break simpleSelectors;
1985                                 if (first) return node || null;
1986                                 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
1987
1988                         } else if (symbol == '.'){
1989
1990                                 if (!this.isHTMLDocument || ((!context.getElementsByClassName || this.brokenGEBCN) && context.querySelectorAll)) break simpleSelectors;
1991                                 if (context.getElementsByClassName && !this.brokenGEBCN){
1992                                         nodes = context.getElementsByClassName(name);
1993                                         if (first) return nodes[0] || null;
1994                                         for (i = 0; node = nodes[i++];){
1995                                                 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
1996                                         }
1997                                 } else {
1998                                         var matchClass = new RegExp('(^|\\s)'+ Slick.escapeRegExp(name) +'(\\s|$)');
1999                                         nodes = context.getElementsByTagName('*');
2000                                         for (i = 0; node = nodes[i++];){
2001                                                 className = node.className;
2002                                                 if (!(className && matchClass.test(className))) continue;
2003                                                 if (first) return node;
2004                                                 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
2005                                         }
2006                                 }
2007
2008                         }
2009
2010                         if (hasOthers) this.sort(found);
2011                         return (first) ? null : found;
2012
2013                 }
2014                 /*</simple-selectors-override>*/
2015
2016                 /*<query-selector-override>*/
2017                 querySelector: if (context.querySelectorAll) {
2018
2019                         if (!this.isHTMLDocument
2020                                 || qsaFailExpCache[expression]
2021                                 //TODO: only skip when expression is actually mixed case
2022                                 || this.brokenMixedCaseQSA
2023                                 || (this.brokenCheckedQSA && expression.indexOf(':checked') > -1)
2024                                 || (this.brokenEmptyAttributeQSA && reEmptyAttribute.test(expression))
2025                                 || (!contextIsDocument //Abort when !contextIsDocument and...
2026                                         //  there are multiple expressions in the selector
2027                                         //  since we currently only fix non-document rooted QSA for single expression selectors
2028                                         && expression.indexOf(',') > -1
2029                                 )
2030                                 || Slick.disableQSA
2031                         ) break querySelector;
2032
2033                         var _expression = expression, _context = context;
2034                         if (!contextIsDocument){
2035                                 // non-document rooted QSA
2036                                 // credits to Andrew Dupont
2037                                 var currentId = _context.getAttribute('id'), slickid = 'slickid__';
2038                                 _context.setAttribute('id', slickid);
2039                                 _expression = '#' + slickid + ' ' + _expression;
2040                                 context = _context.parentNode;
2041                         }
2042
2043                         try {
2044                                 if (first) return context.querySelector(_expression) || null;
2045                                 else nodes = context.querySelectorAll(_expression);
2046                         } catch(e) {
2047                                 qsaFailExpCache[expression] = 1;
2048                                 break querySelector;
2049                         } finally {
2050                                 if (!contextIsDocument){
2051                                         if (currentId) _context.setAttribute('id', currentId);
2052                                         else _context.removeAttribute('id');
2053                                         context = _context;
2054                                 }
2055                         }
2056
2057                         if (this.starSelectsClosedQSA) for (i = 0; node = nodes[i++];){
2058                                 if (node.nodeName > '@' && !(hasOthers && uniques[this.getUID(node)])) found.push(node);
2059                         } else for (i = 0; node = nodes[i++];){
2060                                 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
2061                         }
2062
2063                         if (hasOthers) this.sort(found);
2064                         return found;
2065
2066                 }
2067                 /*</query-selector-override>*/
2068
2069                 parsed = this.Slick.parse(expression);
2070                 if (!parsed.length) return found;
2071         } else if (expression == null){ // there is no expression
2072                 return found;
2073         } else if (expression.Slick){ // expression is a parsed Slick object
2074                 parsed = expression;
2075         } else if (this.contains(context.documentElement || context, expression)){ // expression is a node
2076                 (found) ? found.push(expression) : found = expression;
2077                 return found;
2078         } else { // other junk
2079                 return found;
2080         }
2081
2082         /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/
2083
2084         // cache elements for the nth selectors
2085
2086         this.posNTH = {};
2087         this.posNTHLast = {};
2088         this.posNTHType = {};
2089         this.posNTHTypeLast = {};
2090
2091         /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/
2092
2093         // if append is null and there is only a single selector with one expression use pushArray, else use pushUID
2094         this.push = (!hasOthers && (first || (parsed.length == 1 && parsed.expressions[0].length == 1))) ? this.pushArray : this.pushUID;
2095
2096         if (found == null) found = [];
2097
2098         // default engine
2099
2100         var j, m, n;
2101         var combinator, tag, id, classList, classes, attributes, pseudos;
2102         var currentItems, currentExpression, currentBit, lastBit, expressions = parsed.expressions;
2103
2104         search: for (i = 0; (currentExpression = expressions[i]); i++) for (j = 0; (currentBit = currentExpression[j]); j++){
2105
2106                 combinator = 'combinator:' + currentBit.combinator;
2107                 if (!this[combinator]) continue search;
2108
2109                 tag        = (this.isXMLDocument) ? currentBit.tag : currentBit.tag.toUpperCase();
2110                 id         = currentBit.id;
2111                 classList  = currentBit.classList;
2112                 classes    = currentBit.classes;
2113                 attributes = currentBit.attributes;
2114                 pseudos    = currentBit.pseudos;
2115                 lastBit    = (j === (currentExpression.length - 1));
2116
2117                 this.bitUniques = {};
2118
2119                 if (lastBit){
2120                         this.uniques = uniques;
2121                         this.found = found;
2122                 } else {
2123                         this.uniques = {};
2124                         this.found = [];
2125                 }
2126
2127                 if (j === 0){
2128                         this[combinator](context, tag, id, classes, attributes, pseudos, classList);
2129                         if (first && lastBit && found.length) break search;
2130                 } else {
2131                         if (first && lastBit) for (m = 0, n = currentItems.length; m < n; m++){
2132                                 this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
2133                                 if (found.length) break search;
2134                         } else for (m = 0, n = currentItems.length; m < n; m++) this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
2135                 }
2136
2137                 currentItems = this.found;
2138         }
2139
2140         // should sort if there are nodes in append and if you pass multiple expressions.
2141         if (hasOthers || (parsed.expressions.length > 1)) this.sort(found);
2142
2143         return (first) ? (found[0] || null) : found;
2144 };
2145
2146 // Utils
2147
2148 local.uidx = 1;
2149 local.uidk = 'slick-uniqueid';
2150
2151 local.getUIDXML = function(node){
2152         var uid = node.getAttribute(this.uidk);
2153         if (!uid){
2154                 uid = this.uidx++;
2155                 node.setAttribute(this.uidk, uid);
2156         }
2157         return uid;
2158 };
2159
2160 local.getUIDHTML = function(node){
2161         return node.uniqueNumber || (node.uniqueNumber = this.uidx++);
2162 };
2163
2164 // sort based on the setDocument documentSorter method.
2165
2166 local.sort = function(results){
2167         if (!this.documentSorter) return results;
2168         results.sort(this.documentSorter);
2169         return results;
2170 };
2171
2172 /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/
2173
2174 local.cacheNTH = {};
2175
2176 local.matchNTH = /^([+-]?\d*)?([a-z]+)?([+-]\d+)?$/;
2177
2178 local.parseNTHArgument = function(argument){
2179         var parsed = argument.match(this.matchNTH);
2180         if (!parsed) return false;
2181         var special = parsed[2] || false;
2182         var a = parsed[1] || 1;
2183         if (a == '-') a = -1;
2184         var b = +parsed[3] || 0;
2185         parsed =
2186                 (special == 'n')        ? {a: a, b: b} :
2187                 (special == 'odd')      ? {a: 2, b: 1} :
2188                 (special == 'even')     ? {a: 2, b: 0} : {a: 0, b: a};
2189
2190         return (this.cacheNTH[argument] = parsed);
2191 };
2192
2193 local.createNTHPseudo = function(child, sibling, positions, ofType){
2194         return function(node, argument){
2195                 var uid = this.getUID(node);
2196                 if (!this[positions][uid]){
2197                         var parent = node.parentNode;
2198                         if (!parent) return false;
2199                         var el = parent[child], count = 1;
2200                         if (ofType){
2201                                 var nodeName = node.nodeName;
2202                                 do {
2203                                         if (el.nodeName != nodeName) continue;
2204                                         this[positions][this.getUID(el)] = count++;
2205                                 } while ((el = el[sibling]));
2206                         } else {
2207                                 do {
2208                                         if (el.nodeType != 1) continue;
2209                                         this[positions][this.getUID(el)] = count++;
2210                                 } while ((el = el[sibling]));
2211                         }
2212                 }
2213                 argument = argument || 'n';
2214                 var parsed = this.cacheNTH[argument] || this.parseNTHArgument(argument);
2215                 if (!parsed) return false;
2216                 var a = parsed.a, b = parsed.b, pos = this[positions][uid];
2217                 if (a == 0) return b == pos;
2218                 if (a > 0){
2219                         if (pos < b) return false;
2220                 } else {
2221                         if (b < pos) return false;
2222                 }
2223                 return ((pos - b) % a) == 0;
2224         };
2225 };
2226
2227 /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/
2228
2229 local.pushArray = function(node, tag, id, classes, attributes, pseudos){
2230         if (this.matchSelector(node, tag, id, classes, attributes, pseudos)) this.found.push(node);
2231 };
2232
2233 local.pushUID = function(node, tag, id, classes, attributes, pseudos){
2234         var uid = this.getUID(node);
2235         if (!this.uniques[uid] && this.matchSelector(node, tag, id, classes, attributes, pseudos)){
2236                 this.uniques[uid] = true;
2237                 this.found.push(node);
2238         }
2239 };
2240
2241 local.matchNode = function(node, selector){
2242         if (this.isHTMLDocument && this.nativeMatchesSelector){
2243                 try {
2244                         return this.nativeMatchesSelector.call(node, selector.replace(/\[([^=]+)=\s*([^'"\]]+?)\s*\]/g, '[$1="$2"]'));
2245                 } catch(matchError) {}
2246         }
2247
2248         var parsed = this.Slick.parse(selector);
2249         if (!parsed) return true;
2250
2251         // simple (single) selectors
2252         var expressions = parsed.expressions, simpleExpCounter = 0, i;
2253         for (i = 0; (currentExpression = expressions[i]); i++){
2254                 if (currentExpression.length == 1){
2255                         var exp = currentExpression[0];
2256                         if (this.matchSelector(node, (this.isXMLDocument) ? exp.tag : exp.tag.toUpperCase(), exp.id, exp.classes, exp.attributes, exp.pseudos)) return true;
2257                         simpleExpCounter++;
2258                 }
2259         }
2260
2261         if (simpleExpCounter == parsed.length) return false;
2262
2263         var nodes = this.search(this.document, parsed), item;
2264         for (i = 0; item = nodes[i++];){
2265                 if (item === node) return true;
2266         }
2267         return false;
2268 };
2269
2270 local.matchPseudo = function(node, name, argument){
2271         var pseudoName = 'pseudo:' + name;
2272         if (this[pseudoName]) return this[pseudoName](node, argument);
2273         var attribute = this.getAttribute(node, name);
2274         return (argument) ? argument == attribute : !!attribute;
2275 };
2276
2277 local.matchSelector = function(node, tag, id, classes, attributes, pseudos){
2278         if (tag){
2279                 var nodeName = (this.isXMLDocument) ? node.nodeName : node.nodeName.toUpperCase();
2280                 if (tag == '*'){
2281                         if (nodeName < '@') return false; // Fix for comment nodes and closed nodes
2282                 } else {
2283                         if (nodeName != tag) return false;
2284                 }
2285         }
2286
2287         if (id && node.getAttribute('id') != id) return false;
2288
2289         var i, part, cls;
2290         if (classes) for (i = classes.length; i--;){
2291                 cls = this.getAttribute(node, 'class');
2292                 if (!(cls && classes[i].regexp.test(cls))) return false;
2293         }
2294         if (attributes) for (i = attributes.length; i--;){
2295                 part = attributes[i];
2296                 if (part.operator ? !part.test(this.getAttribute(node, part.key)) : !this.hasAttribute(node, part.key)) return false;
2297         }
2298         if (pseudos) for (i = pseudos.length; i--;){
2299                 part = pseudos[i];
2300                 if (!this.matchPseudo(node, part.key, part.value)) return false;
2301         }
2302         return true;
2303 };
2304
2305 var combinators = {
2306
2307         ' ': function(node, tag, id, classes, attributes, pseudos, classList){ // all child nodes, any level
2308
2309                 var i, item, children;
2310
2311                 if (this.isHTMLDocument){
2312                         getById: if (id){
2313                                 item = this.document.getElementById(id);
2314                                 if ((!item && node.all) || (this.idGetsName && item && item.getAttributeNode('id').nodeValue != id)){
2315                                         // all[id] returns all the elements with that name or id inside node
2316                                         // if theres just one it will return the element, else it will be a collection
2317                                         children = node.all[id];
2318                                         if (!children) return;
2319                                         if (!children[0]) children = [children];
2320                                         for (i = 0; item = children[i++];){
2321                                                 var idNode = item.getAttributeNode('id');
2322                                                 if (idNode && idNode.nodeValue == id){
2323                                                         this.push(item, tag, null, classes, attributes, pseudos);
2324                                                         break;
2325                                                 }
2326                                         }
2327                                         return;
2328                                 }
2329                                 if (!item){
2330                                         // if the context is in the dom we return, else we will try GEBTN, breaking the getById label
2331                                         if (this.contains(this.root, node)) return;
2332                                         else break getById;
2333                                 } else if (this.document !== node && !this.contains(node, item)) return;
2334                                 this.push(item, tag, null, classes, attributes, pseudos);
2335                                 return;
2336                         }
2337                         getByClass: if (classes && node.getElementsByClassName && !this.brokenGEBCN){
2338                                 children = node.getElementsByClassName(classList.join(' '));
2339                                 if (!(children && children.length)) break getByClass;
2340                                 for (i = 0; item = children[i++];) this.push(item, tag, id, null, attributes, pseudos);
2341                                 return;
2342                         }
2343                 }
2344                 getByTag: {
2345                         children = node.getElementsByTagName(tag);
2346                         if (!(children && children.length)) break getByTag;
2347                         if (!this.brokenStarGEBTN) tag = null;
2348                         for (i = 0; item = children[i++];) this.push(item, tag, id, classes, attributes, pseudos);
2349                 }
2350         },
2351
2352         '>': function(node, tag, id, classes, attributes, pseudos){ // direct children
2353                 if ((node = node.firstChild)) do {
2354                         if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
2355                 } while ((node = node.nextSibling));
2356         },
2357
2358         '+': function(node, tag, id, classes, attributes, pseudos){ // next sibling
2359                 while ((node = node.nextSibling)) if (node.nodeType == 1){
2360                         this.push(node, tag, id, classes, attributes, pseudos);
2361                         break;
2362                 }
2363         },
2364
2365         '^': function(node, tag, id, classes, attributes, pseudos){ // first child
2366                 node = node.firstChild;
2367                 if (node){
2368                         if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
2369                         else this['combinator:+'](node, tag, id, classes, attributes, pseudos);
2370                 }
2371         },
2372
2373         '~': function(node, tag, id, classes, attributes, pseudos){ // next siblings
2374                 while ((node = node.nextSibling)){
2375                         if (node.nodeType != 1) continue;
2376                         var uid = this.getUID(node);
2377                         if (this.bitUniques[uid]) break;
2378                         this.bitUniques[uid] = true;
2379                         this.push(node, tag, id, classes, attributes, pseudos);
2380                 }
2381         },
2382
2383         '++': function(node, tag, id, classes, attributes, pseudos){ // next sibling and previous sibling
2384                 this['combinator:+'](node, tag, id, classes, attributes, pseudos);
2385                 this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
2386         },
2387
2388         '~~': function(node, tag, id, classes, attributes, pseudos){ // next siblings and previous siblings
2389                 this['combinator:~'](node, tag, id, classes, attributes, pseudos);
2390                 this['combinator:!~'](node, tag, id, classes, attributes, pseudos);
2391         },
2392
2393         '!': function(node, tag, id, classes, attributes, pseudos){ // all parent nodes up to document
2394                 while ((node = node.parentNode)) if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos);
2395         },
2396
2397         '!>': function(node, tag, id, classes, attributes, pseudos){ // direct parent (one level)
2398                 node = node.parentNode;
2399                 if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos);
2400         },
2401
2402         '!+': function(node, tag, id, classes, attributes, pseudos){ // previous sibling
2403                 while ((node = node.previousSibling)) if (node.nodeType == 1){
2404                         this.push(node, tag, id, classes, attributes, pseudos);
2405                         break;
2406                 }
2407         },
2408
2409         '!^': function(node, tag, id, classes, attributes, pseudos){ // last child
2410                 node = node.lastChild;
2411                 if (node){
2412                         if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
2413                         else this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
2414                 }
2415         },
2416
2417         '!~': function(node, tag, id, classes, attributes, pseudos){ // previous siblings
2418                 while ((node = node.previousSibling)){
2419                         if (node.nodeType != 1) continue;
2420                         var uid = this.getUID(node);
2421                         if (this.bitUniques[uid]) break;
2422                         this.bitUniques[uid] = true;
2423                         this.push(node, tag, id, classes, attributes, pseudos);
2424                 }
2425         }
2426
2427 };
2428
2429 for (var c in combinators) local['combinator:' + c] = combinators[c];
2430
2431 var pseudos = {
2432
2433         /*<pseudo-selectors>*/
2434
2435         'empty': function(node){
2436                 var child = node.firstChild;
2437                 return !(child && child.nodeType == 1) && !(node.innerText || node.textContent || '').length;
2438         },
2439
2440         'not': function(node, expression){
2441                 return !this.matchNode(node, expression);
2442         },
2443
2444         'contains': function(node, text){
2445                 return (node.innerText || node.textContent || '').indexOf(text) > -1;
2446         },
2447
2448         'first-child': function(node){
2449                 while ((node = node.previousSibling)) if (node.nodeType == 1) return false;
2450                 return true;
2451         },
2452
2453         'last-child': function(node){
2454                 while ((node = node.nextSibling)) if (node.nodeType == 1) return false;
2455                 return true;
2456         },
2457
2458         'only-child': function(node){
2459                 var prev = node;
2460                 while ((prev = prev.previousSibling)) if (prev.nodeType == 1) return false;
2461                 var next = node;
2462                 while ((next = next.nextSibling)) if (next.nodeType == 1) return false;
2463                 return true;
2464         },
2465
2466         /*<nth-pseudo-selectors>*/
2467
2468         'nth-child': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTH'),
2469
2470         'nth-last-child': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHLast'),
2471
2472         'nth-of-type': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTHType', true),
2473
2474         'nth-last-of-type': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHTypeLast', true),
2475
2476         'index': function(node, index){
2477                 return this['pseudo:nth-child'](node, '' + (index + 1));
2478         },
2479
2480         'even': function(node){
2481                 return this['pseudo:nth-child'](node, '2n');
2482         },
2483
2484         'odd': function(node){
2485                 return this['pseudo:nth-child'](node, '2n+1');
2486         },
2487
2488         /*</nth-pseudo-selectors>*/
2489
2490         /*<of-type-pseudo-selectors>*/
2491
2492         'first-of-type': function(node){
2493                 var nodeName = node.nodeName;
2494                 while ((node = node.previousSibling)) if (node.nodeName == nodeName) return false;
2495                 return true;
2496         },
2497
2498         'last-of-type': function(node){
2499                 var nodeName = node.nodeName;
2500                 while ((node = node.nextSibling)) if (node.nodeName == nodeName) return false;
2501                 return true;
2502         },
2503
2504         'only-of-type': function(node){
2505                 var prev = node, nodeName = node.nodeName;
2506                 while ((prev = prev.previousSibling)) if (prev.nodeName == nodeName) return false;
2507                 var next = node;
2508                 while ((next = next.nextSibling)) if (next.nodeName == nodeName) return false;
2509                 return true;
2510         },
2511
2512         /*</of-type-pseudo-selectors>*/
2513
2514         // custom pseudos
2515
2516         'enabled': function(node){
2517                 return !node.disabled;
2518         },
2519
2520         'disabled': function(node){
2521                 return node.disabled;
2522         },
2523
2524         'checked': function(node){
2525                 return node.checked || node.selected;
2526         },
2527
2528         'focus': function(node){
2529                 return this.isHTMLDocument && this.document.activeElement === node && (node.href || node.type || this.hasAttribute(node, 'tabindex'));
2530         },
2531
2532         'root': function(node){
2533                 return (node === this.root);
2534         },
2535
2536         'selected': function(node){
2537                 return node.selected;
2538         }
2539
2540         /*</pseudo-selectors>*/
2541 };
2542
2543 for (var p in pseudos) local['pseudo:' + p] = pseudos[p];
2544
2545 // attributes methods
2546
2547 var attributeGetters = local.attributeGetters = {
2548
2549         'for': function(){
2550                 return ('htmlFor' in this) ? this.htmlFor : this.getAttribute('for');
2551         },
2552
2553         'href': function(){
2554                 return ('href' in this) ? this.getAttribute('href', 2) : this.getAttribute('href');
2555         },
2556
2557         'style': function(){
2558                 return (this.style) ? this.style.cssText : this.getAttribute('style');
2559         },
2560
2561         'tabindex': function(){
2562                 var attributeNode = this.getAttributeNode('tabindex');
2563                 return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null;
2564         },
2565
2566         'type': function(){
2567                 return this.getAttribute('type');
2568         },
2569
2570         'maxlength': function(){
2571                 var attributeNode = this.getAttributeNode('maxLength');
2572                 return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null;
2573         }
2574
2575 };
2576
2577 attributeGetters.MAXLENGTH = attributeGetters.maxLength = attributeGetters.maxlength;
2578
2579 // Slick
2580
2581 var Slick = local.Slick = (this.Slick || {});
2582
2583 Slick.version = '1.1.7';
2584
2585 // Slick finder
2586
2587 Slick.search = function(context, expression, append){
2588         return local.search(context, expression, append);
2589 };
2590
2591 Slick.find = function(context, expression){
2592         return local.search(context, expression, null, true);
2593 };
2594
2595 // Slick containment checker
2596
2597 Slick.contains = function(container, node){
2598         local.setDocument(container);
2599         return local.contains(container, node);
2600 };
2601
2602 // Slick attribute getter
2603
2604 Slick.getAttribute = function(node, name){
2605         local.setDocument(node);
2606         return local.getAttribute(node, name);
2607 };
2608
2609 Slick.hasAttribute = function(node, name){
2610         local.setDocument(node);
2611         return local.hasAttribute(node, name);
2612 };
2613
2614 // Slick matcher
2615
2616 Slick.match = function(node, selector){
2617         if (!(node && selector)) return false;
2618         if (!selector || selector === node) return true;
2619         local.setDocument(node);
2620         return local.matchNode(node, selector);
2621 };
2622
2623 // Slick attribute accessor
2624
2625 Slick.defineAttributeGetter = function(name, fn){
2626         local.attributeGetters[name] = fn;
2627         return this;
2628 };
2629
2630 Slick.lookupAttributeGetter = function(name){
2631         return local.attributeGetters[name];
2632 };
2633
2634 // Slick pseudo accessor
2635
2636 Slick.definePseudo = function(name, fn){
2637         local['pseudo:' + name] = function(node, argument){
2638                 return fn.call(node, argument);
2639         };
2640         return this;
2641 };
2642
2643 Slick.lookupPseudo = function(name){
2644         var pseudo = local['pseudo:' + name];
2645         if (pseudo) return function(argument){
2646                 return pseudo.call(this, argument);
2647         };
2648         return null;
2649 };
2650
2651 // Slick overrides accessor
2652
2653 Slick.override = function(regexp, fn){
2654         local.override(regexp, fn);
2655         return this;
2656 };
2657
2658 Slick.isXML = local.isXML;
2659
2660 Slick.uidOf = function(node){
2661         return local.getUIDHTML(node);
2662 };
2663
2664 if (!this.Slick) this.Slick = Slick;
2665
2666 }).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);
2667
2668
2669 // Begin: Source/Element/Element.js
2670 /*
2671 ---
2672
2673 name: Element
2674
2675 description: One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser, time-saver methods to let you easily work with HTML Elements.
2676
2677 license: MIT-style license.
2678
2679 requires: [Window, Document, Array, String, Function, Object, Number, Slick.Parser, Slick.Finder]
2680
2681 provides: [Element, Elements, $, $$, Iframe, Selectors]
2682
2683 ...
2684 */
2685
2686 var Element = function(tag, props){
2687         var konstructor = Element.Constructors[tag];
2688         if (konstructor) return konstructor(props);
2689         if (typeof tag != 'string') return document.id(tag).set(props);
2690
2691         if (!props) props = {};
2692
2693         if (!(/^[\w-]+$/).test(tag)){
2694                 var parsed = Slick.parse(tag).expressions[0][0];
2695                 tag = (parsed.tag == '*') ? 'div' : parsed.tag;
2696                 if (parsed.id && props.id == null) props.id = parsed.id;
2697
2698                 var attributes = parsed.attributes;
2699                 if (attributes) for (var attr, i = 0, l = attributes.length; i < l; i++){
2700                         attr = attributes[i];
2701                         if (props[attr.key] != null) continue;
2702
2703                         if (attr.value != null && attr.operator == '=') props[attr.key] = attr.value;
2704                         else if (!attr.value && !attr.operator) props[attr.key] = true;
2705                 }
2706
2707                 if (parsed.classList && props['class'] == null) props['class'] = parsed.classList.join(' ');
2708         }
2709
2710         return document.newElement(tag, props);
2711 };
2712
2713
2714 if (Browser.Element){
2715         Element.prototype = Browser.Element.prototype;
2716         // IE8 and IE9 require the wrapping.
2717         Element.prototype._fireEvent = (function(fireEvent){
2718                 return function(type, event){
2719                         return fireEvent.call(this, type, event);
2720                 };
2721         })(Element.prototype.fireEvent);
2722 }
2723
2724 new Type('Element', Element).mirror(function(name){
2725         if (Array.prototype[name]) return;
2726
2727         var obj = {};
2728         obj[name] = function(){
2729                 var results = [], args = arguments, elements = true;
2730                 for (var i = 0, l = this.length; i < l; i++){
2731                         var element = this[i], result = results[i] = element[name].apply(element, args);
2732                         elements = (elements && typeOf(result) == 'element');
2733                 }
2734                 return (elements) ? new Elements(results) : results;
2735         };
2736
2737         Elements.implement(obj);
2738 });
2739
2740 if (!Browser.Element){
2741         Element.parent = Object;
2742
2743         Element.Prototype = {
2744                 '$constructor': Element,
2745                 '$family': Function.from('element').hide()
2746         };
2747
2748         Element.mirror(function(name, method){
2749                 Element.Prototype[name] = method;
2750         });
2751 }
2752
2753 Element.Constructors = {};
2754
2755 //<1.2compat>
2756
2757 Element.Constructors = new Hash;
2758
2759 //</1.2compat>
2760
2761 var IFrame = new Type('IFrame', function(){
2762         var params = Array.link(arguments, {
2763                 properties: Type.isObject,
2764                 iframe: function(obj){
2765                         return (obj != null);
2766                 }
2767         });
2768
2769         var props = params.properties || {}, iframe;
2770         if (params.iframe) iframe = document.id(params.iframe);
2771         var onload = props.onload || function(){};
2772         delete props.onload;
2773         props.id = props.name = [props.id, props.name, iframe ? (iframe.id || iframe.name) : 'IFrame_' + String.uniqueID()].pick();
2774         iframe = new Element(iframe || 'iframe', props);
2775
2776         var onLoad = function(){
2777                 onload.call(iframe.contentWindow);
2778         };
2779
2780         if (window.frames[props.id]) onLoad();
2781         else iframe.addListener('load', onLoad);
2782         return iframe;
2783 });
2784
2785 var Elements = this.Elements = function(nodes){
2786         if (nodes && nodes.length){
2787                 var uniques = {}, node;
2788                 for (var i = 0; node = nodes[i++];){
2789                         var uid = Slick.uidOf(node);
2790                         if (!uniques[uid]){
2791                                 uniques[uid] = true;
2792                                 this.push(node);
2793                         }
2794                 }
2795         }
2796 };
2797
2798 Elements.prototype = {length: 0};
2799 Elements.parent = Array;
2800
2801 new Type('Elements', Elements).implement({
2802
2803         filter: function(filter, bind){
2804                 if (!filter) return this;
2805                 return new Elements(Array.filter(this, (typeOf(filter) == 'string') ? function(item){
2806                         return item.match(filter);
2807                 } : filter, bind));
2808         }.protect(),
2809
2810         push: function(){
2811                 var length = this.length;
2812                 for (var i = 0, l = arguments.length; i < l; i++){
2813                         var item = document.id(arguments[i]);
2814                         if (item) this[length++] = item;
2815                 }
2816                 return (this.length = length);
2817         }.protect(),
2818
2819         unshift: function(){
2820                 var items = [];
2821                 for (var i = 0, l = arguments.length; i < l; i++){
2822                         var item = document.id(arguments[i]);
2823                         if (item) items.push(item);
2824                 }
2825                 return Array.prototype.unshift.apply(this, items);
2826         }.protect(),
2827
2828         concat: function(){
2829                 var newElements = new Elements(this);
2830                 for (var i = 0, l = arguments.length; i < l; i++){
2831                         var item = arguments[i];
2832                         if (Type.isEnumerable(item)) newElements.append(item);
2833                         else newElements.push(item);
2834                 }
2835                 return newElements;
2836         }.protect(),
2837
2838         append: function(collection){
2839                 for (var i = 0, l = collection.length; i < l; i++) this.push(collection[i]);
2840                 return this;
2841         }.protect(),
2842
2843         empty: function(){
2844                 while (this.length) delete this[--this.length];
2845                 return this;
2846         }.protect()
2847
2848 });
2849
2850 //<1.2compat>
2851
2852 Elements.alias('extend', 'append');
2853
2854 //</1.2compat>
2855
2856 (function(){
2857
2858 // FF, IE
2859 var splice = Array.prototype.splice, object = {'0': 0, '1': 1, length: 2};
2860
2861 splice.call(object, 1, 1);
2862 if (object[1] == 1) Elements.implement('splice', function(){
2863         var length = this.length;
2864         var result = splice.apply(this, arguments);
2865         while (length >= this.length) delete this[length--];
2866         return result;
2867 }.protect());
2868
2869 Array.forEachMethod(function(method, name){
2870         Elements.implement(name, method);
2871 });
2872
2873 Array.mirror(Elements);
2874
2875 /*<ltIE8>*/
2876 var createElementAcceptsHTML;
2877 try {
2878     createElementAcceptsHTML = (document.createElement('<input name=x>').name == 'x');
2879 } catch (e){}
2880
2881 var escapeQuotes = function(html){
2882         return ('' + html).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
2883 };
2884 /*</ltIE8>*/
2885
2886 Document.implement({
2887
2888         newElement: function(tag, props){
2889                 if (props && props.checked != null) props.defaultChecked = props.checked;
2890                 /*<ltIE8>*/// Fix for readonly name and type properties in IE < 8
2891                 if (createElementAcceptsHTML && props){
2892                         tag = '<' + tag;
2893                         if (props.name) tag += ' name="' + escapeQuotes(props.name) + '"';
2894                         if (props.type) tag += ' type="' + escapeQuotes(props.type) + '"';
2895                         tag += '>';
2896                         delete props.name;
2897                         delete props.type;
2898                 }
2899                 /*</ltIE8>*/
2900                 return this.id(this.createElement(tag)).set(props);
2901         }
2902
2903 });
2904
2905 })();
2906
2907 (function(){
2908
2909 Slick.uidOf(window);
2910 Slick.uidOf(document);
2911
2912 Document.implement({
2913
2914         newTextNode: function(text){
2915                 return this.createTextNode(text);
2916         },
2917
2918         getDocument: function(){
2919                 return this;
2920         },
2921
2922         getWindow: function(){
2923                 return this.window;
2924         },
2925
2926         id: (function(){
2927
2928                 var types = {
2929
2930                         string: function(id, nocash, doc){
2931                                 id = Slick.find(doc, '#' + id.replace(/(\W)/g, '\\$1'));
2932                                 return (id) ? types.element(id, nocash) : null;
2933                         },
2934
2935                         element: function(el, nocash){
2936                                 Slick.uidOf(el);
2937                                 if (!nocash && !el.$family && !(/^(?:object|embed)$/i).test(el.tagName)){
2938                                         var fireEvent = el.fireEvent;
2939                                         // wrapping needed in IE7, or else crash
2940                                         el._fireEvent = function(type, event){
2941                                                 return fireEvent(type, event);
2942                                         };
2943                                         Object.append(el, Element.Prototype);
2944                                 }
2945                                 return el;
2946                         },
2947
2948                         object: function(obj, nocash, doc){
2949                                 if (obj.toElement) return types.element(obj.toElement(doc), nocash);
2950                                 return null;
2951                         }
2952
2953                 };
2954
2955                 types.textnode = types.whitespace = types.window = types.document = function(zero){
2956                         return zero;
2957                 };
2958
2959                 return function(el, nocash, doc){
2960                         if (el && el.$family && el.uniqueNumber) return el;
2961                         var type = typeOf(el);
2962                         return (types[type]) ? types[type](el, nocash, doc || document) : null;
2963                 };
2964
2965         })()
2966
2967 });
2968
2969 if (window.$ == null) Window.implement('$', function(el, nc){
2970         return document.id(el, nc, this.document);
2971 });
2972
2973 Window.implement({
2974
2975         getDocument: function(){
2976                 return this.document;
2977         },
2978
2979         getWindow: function(){
2980                 return this;
2981         }
2982
2983 });
2984
2985 [Document, Element].invoke('implement', {
2986
2987         getElements: function(expression){
2988                 return Slick.search(this, expression, new Elements);
2989         },
2990
2991         getElement: function(expression){
2992                 return document.id(Slick.find(this, expression));
2993         }
2994
2995 });
2996
2997 var contains = {contains: function(element){
2998         return Slick.contains(this, element);
2999 }};
3000
3001 if (!document.contains) Document.implement(contains);
3002 if (!document.createElement('div').contains) Element.implement(contains);
3003
3004 //<1.2compat>
3005
3006 Element.implement('hasChild', function(element){
3007         return this !== element && this.contains(element);
3008 });
3009
3010 (function(search, find, match){
3011
3012         this.Selectors = {};
3013         var pseudos = this.Selectors.Pseudo = new Hash();
3014
3015         var addSlickPseudos = function(){
3016                 for (var name in pseudos) if (pseudos.hasOwnProperty(name)){
3017                         Slick.definePseudo(name, pseudos[name]);
3018                         delete pseudos[name];
3019                 }
3020         };
3021
3022         Slick.search = function(context, expression, append){
3023                 addSlickPseudos();
3024                 return search.call(this, context, expression, append);
3025         };
3026
3027         Slick.find = function(context, expression){
3028                 addSlickPseudos();
3029                 return find.call(this, context, expression);
3030         };
3031
3032         Slick.match = function(node, selector){
3033                 addSlickPseudos();
3034                 return match.call(this, node, selector);
3035         };
3036
3037 })(Slick.search, Slick.find, Slick.match);
3038
3039 //</1.2compat>
3040
3041 // tree walking
3042
3043 var injectCombinator = function(expression, combinator){
3044         if (!expression) return combinator;
3045
3046         expression = Object.clone(Slick.parse(expression));
3047
3048         var expressions = expression.expressions;
3049         for (var i = expressions.length; i--;)
3050                 expressions[i][0].combinator = combinator;
3051
3052         return expression;
3053 };
3054
3055 Object.forEach({
3056         getNext: '~',
3057         getPrevious: '!~',
3058         getParent: '!'
3059 }, function(combinator, method){
3060         Element.implement(method, function(expression){
3061                 return this.getElement(injectCombinator(expression, combinator));
3062         });
3063 });
3064
3065 Object.forEach({
3066         getAllNext: '~',
3067         getAllPrevious: '!~',
3068         getSiblings: '~~',
3069         getChildren: '>',
3070         getParents: '!'
3071 }, function(combinator, method){
3072         Element.implement(method, function(expression){
3073                 return this.getElements(injectCombinator(expression, combinator));
3074         });
3075 });
3076
3077 Element.implement({
3078
3079         getFirst: function(expression){
3080                 return document.id(Slick.search(this, injectCombinator(expression, '>'))[0]);
3081         },
3082
3083         getLast: function(expression){
3084                 return document.id(Slick.search(this, injectCombinator(expression, '>')).getLast());
3085         },
3086
3087         getWindow: function(){
3088                 return this.ownerDocument.window;
3089         },
3090
3091         getDocument: function(){
3092                 return this.ownerDocument;
3093         },
3094
3095         getElementById: function(id){
3096                 return document.id(Slick.find(this, '#' + ('' + id).replace(/(\W)/g, '\\$1')));
3097         },
3098
3099         match: function(expression){
3100                 return !expression || Slick.match(this, expression);
3101         }
3102
3103 });
3104
3105 //<1.2compat>
3106
3107 if (window.$$ == null) Window.implement('$$', function(selector){
3108         var elements = new Elements;
3109         if (arguments.length == 1 && typeof selector == 'string') return Slick.search(this.document, selector, elements);
3110         var args = Array.flatten(arguments);
3111         for (var i = 0, l = args.length; i < l; i++){
3112                 var item = args[i];
3113                 switch (typeOf(item)){
3114                         case 'element': elements.push(item); break;
3115                         case 'string': Slick.search(this.document, item, elements);
3116                 }
3117         }
3118         return elements;
3119 });
3120
3121 //</1.2compat>
3122
3123 if (window.$$ == null) Window.implement('$$', function(selector){
3124         if (arguments.length == 1){
3125                 if (typeof selector == 'string') return Slick.search(this.document, selector, new Elements);
3126                 else if (Type.isEnumerable(selector)) return new Elements(selector);
3127         }
3128         return new Elements(arguments);
3129 });
3130
3131 // Inserters
3132
3133 var inserters = {
3134
3135         before: function(context, element){
3136                 var parent = element.parentNode;
3137                 if (parent) parent.insertBefore(context, element);
3138         },
3139
3140         after: function(context, element){
3141                 var parent = element.parentNode;
3142                 if (parent) parent.insertBefore(context, element.nextSibling);
3143         },
3144
3145         bottom: function(context, element){
3146                 element.appendChild(context);
3147         },
3148
3149         top: function(context, element){
3150                 element.insertBefore(context, element.firstChild);
3151         }
3152
3153 };
3154
3155 inserters.inside = inserters.bottom;
3156
3157 //<1.2compat>
3158
3159 Object.each(inserters, function(inserter, where){
3160
3161         where = where.capitalize();
3162
3163         var methods = {};
3164
3165         methods['inject' + where] = function(el){
3166                 inserter(this, document.id(el, true));
3167                 return this;
3168         };
3169
3170         methods['grab' + where] = function(el){
3171                 inserter(document.id(el, true), this);
3172                 return this;
3173         };
3174
3175         Element.implement(methods);
3176
3177 });
3178
3179 //</1.2compat>
3180
3181 // getProperty / setProperty
3182
3183 var propertyGetters = {}, propertySetters = {};
3184
3185 // properties
3186
3187 var properties = {};
3188 Array.forEach([
3189         'type', 'value', 'defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan',
3190         'frameBorder', 'rowSpan', 'tabIndex', 'useMap'
3191 ], function(property){
3192         properties[property.toLowerCase()] = property;
3193 });
3194
3195 properties.html = 'innerHTML';
3196 properties.text = (document.createElement('div').textContent == null) ? 'innerText': 'textContent';
3197
3198 Object.forEach(properties, function(real, key){
3199         propertySetters[key] = function(node, value){
3200                 node[real] = value;
3201         };
3202         propertyGetters[key] = function(node){
3203                 return node[real];
3204         };
3205 });
3206
3207 // Booleans
3208
3209 var bools = [
3210         'compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked',
3211         'disabled', 'readOnly', 'multiple', 'selected', 'noresize',
3212         'defer', 'defaultChecked', 'autofocus', 'controls', 'autoplay',
3213         'loop'
3214 ];
3215
3216 var booleans = {};
3217 Array.forEach(bools, function(bool){
3218         var lower = bool.toLowerCase();
3219         booleans[lower] = bool;
3220         propertySetters[lower] = function(node, value){
3221                 node[bool] = !!value;
3222         };
3223         propertyGetters[lower] = function(node){
3224                 return !!node[bool];
3225         };
3226 });
3227
3228 // Special cases
3229
3230 Object.append(propertySetters, {
3231
3232         'class': function(node, value){
3233                 ('className' in node) ? node.className = (value || '') : node.setAttribute('class', value);
3234         },
3235
3236         'for': function(node, value){
3237                 ('htmlFor' in node) ? node.htmlFor = value : node.setAttribute('for', value);
3238         },
3239
3240         'style': function(node, value){
3241                 (node.style) ? node.style.cssText = value : node.setAttribute('style', value);
3242         },
3243
3244         'value': function(node, value){
3245                 node.value = (value != null) ? value : '';
3246         }
3247
3248 });
3249
3250 propertyGetters['class'] = function(node){
3251         return ('className' in node) ? node.className || null : node.getAttribute('class');
3252 };
3253
3254 /* <webkit> */
3255 var el = document.createElement('button');
3256 // IE sets type as readonly and throws
3257 try { el.type = 'button'; } catch(e){}
3258 if (el.type != 'button') propertySetters.type = function(node, value){
3259         node.setAttribute('type', value);
3260 };
3261 el = null;
3262 /* </webkit> */
3263
3264 /*<IE>*/
3265 var input = document.createElement('input');
3266 input.value = 't';
3267 input.type = 'submit';
3268 if (input.value != 't') propertySetters.type = function(node, type){
3269         var value = node.value;
3270         node.type = type;
3271         node.value = value;
3272 };
3273 input = null;
3274 /*</IE>*/
3275
3276 /* getProperty, setProperty */
3277
3278 /* <ltIE9> */
3279 var pollutesGetAttribute = (function(div){
3280         div.random = 'attribute';
3281         return (div.getAttribute('random') == 'attribute');
3282 })(document.createElement('div'));
3283
3284 /* <ltIE9> */
3285
3286 Element.implement({
3287
3288         setProperty: function(name, value){
3289                 var setter = propertySetters[name.toLowerCase()];
3290                 if (setter){
3291                         setter(this, value);
3292                 } else {
3293                         /* <ltIE9> */
3294                         if (pollutesGetAttribute) var attributeWhiteList = this.retrieve('$attributeWhiteList', {});
3295                         /* </ltIE9> */
3296
3297                         if (value == null){
3298                                 this.removeAttribute(name);
3299                                 /* <ltIE9> */
3300                                 if (pollutesGetAttribute) delete attributeWhiteList[name];
3301                                 /* </ltIE9> */
3302                         } else {
3303                                 this.setAttribute(name, '' + value);
3304                                 /* <ltIE9> */
3305                                 if (pollutesGetAttribute) attributeWhiteList[name] = true;
3306                                 /* </ltIE9> */
3307                         }
3308                 }
3309                 return this;
3310         },
3311
3312         setProperties: function(attributes){
3313                 for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]);
3314                 return this;
3315         },
3316
3317         getProperty: function(name){
3318                 var getter = propertyGetters[name.toLowerCase()];
3319                 if (getter) return getter(this);
3320                 /* <ltIE9> */
3321                 if (pollutesGetAttribute){
3322                         var attr = this.getAttributeNode(name), attributeWhiteList = this.retrieve('$attributeWhiteList', {});
3323                         if (!attr) return null;
3324                         if (attr.expando && !attributeWhiteList[name]){
3325                                 var outer = this.outerHTML;
3326                                 // segment by the opening tag and find mention of attribute name
3327                                 if (outer.substr(0, outer.search(/\/?['"]?>(?![^<]*<['"])/)).indexOf(name) < 0) return null;
3328                                 attributeWhiteList[name] = true;
3329                         }
3330                 }
3331                 /* </ltIE9> */
3332                 var result = Slick.getAttribute(this, name);
3333                 return (!result && !Slick.hasAttribute(this, name)) ? null : result;
3334         },
3335
3336         getProperties: function(){
3337                 var args = Array.from(arguments);
3338                 return args.map(this.getProperty, this).associate(args);
3339         },
3340
3341         removeProperty: function(name){
3342                 return this.setProperty(name, null);
3343         },
3344
3345         removeProperties: function(){
3346                 Array.each(arguments, this.removeProperty, this);
3347                 return this;
3348         },
3349
3350         set: function(prop, value){
3351                 var property = Element.Properties[prop];
3352                 (property && property.set) ? property.set.call(this, value) : this.setProperty(prop, value);
3353         }.overloadSetter(),
3354
3355         get: function(prop){
3356                 var property = Element.Properties[prop];
3357                 return (property && property.get) ? property.get.apply(this) : this.getProperty(prop);
3358         }.overloadGetter(),
3359
3360         erase: function(prop){
3361                 var property = Element.Properties[prop];
3362                 (property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop);
3363                 return this;
3364         },
3365
3366         hasClass: function(className){
3367                 return this.className.clean().contains(className, ' ');
3368         },
3369
3370         addClass: function(className){
3371                 if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean();
3372                 return this;
3373         },
3374
3375         removeClass: function(className){
3376                 this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1');
3377                 return this;
3378         },
3379
3380         toggleClass: function(className, force){
3381                 if (force == null) force = !this.hasClass(className);
3382                 return (force) ? this.addClass(className) : this.removeClass(className);
3383         },
3384
3385         adopt: function(){
3386                 var parent = this, fragment, elements = Array.flatten(arguments), length = elements.length;
3387                 if (length > 1) parent = fragment = document.createDocumentFragment();
3388
3389                 for (var i = 0; i < length; i++){
3390                         var element = document.id(elements[i], true);
3391                         if (element) parent.appendChild(element);
3392                 }
3393
3394                 if (fragment) this.appendChild(fragment);
3395
3396                 return this;
3397         },
3398
3399         appendText: function(text, where){
3400                 return this.grab(this.getDocument().newTextNode(text), where);
3401         },
3402
3403         grab: function(el, where){
3404                 inserters[where || 'bottom'](document.id(el, true), this);
3405                 return this;
3406         },
3407
3408         inject: function(el, where){
3409                 inserters[where || 'bottom'](this, document.id(el, true));
3410                 return this;
3411         },
3412
3413         replaces: function(el){
3414                 el = document.id(el, true);
3415                 el.parentNode.replaceChild(this, el);
3416                 return this;
3417         },
3418
3419         wraps: function(el, where){
3420                 el = document.id(el, true);
3421                 return this.replaces(el).grab(el, where);
3422         },
3423
3424         getSelected: function(){
3425                 this.selectedIndex; // Safari 3.2.1
3426                 return new Elements(Array.from(this.options).filter(function(option){
3427                         return option.selected;
3428                 }));
3429         },
3430
3431         toQueryString: function(){
3432                 var queryString = [];
3433                 this.getElements('input, select, textarea').each(function(el){
3434                         var type = el.type;
3435                         if (!el.name || el.disabled || type == 'submit' || type == 'reset' || type == 'file' || type == 'image') return;
3436
3437                         var value = (el.get('tag') == 'select') ? el.getSelected().map(function(opt){
3438                                 // IE
3439                                 return document.id(opt).get('value');
3440                         }) : ((type == 'radio' || type == 'checkbox') && !el.checked) ? null : el.get('value');
3441
3442                         Array.from(value).each(function(val){
3443                                 if (typeof val != 'undefined') queryString.push(encodeURIComponent(el.name) + '=' + encodeURIComponent(val));
3444                         });
3445                 });
3446                 return queryString.join('&');
3447         }
3448
3449 });
3450
3451 var collected = {}, storage = {};
3452
3453 var get = function(uid){
3454         return (storage[uid] || (storage[uid] = {}));
3455 };
3456
3457 var clean = function(item){
3458         var uid = item.uniqueNumber;
3459         if (item.removeEvents) item.removeEvents();
3460         if (item.clearAttributes) item.clearAttributes();
3461         if (uid != null){
3462                 delete collected[uid];
3463                 delete storage[uid];
3464         }
3465         return item;
3466 };
3467
3468 var formProps = {input: 'checked', option: 'selected', textarea: 'value'};
3469
3470 Element.implement({
3471
3472         destroy: function(){
3473                 var children = clean(this).getElementsByTagName('*');
3474                 Array.each(children, clean);
3475                 Element.dispose(this);
3476                 return null;
3477         },
3478
3479         empty: function(){
3480                 Array.from(this.childNodes).each(Element.dispose);
3481                 return this;
3482         },
3483
3484         dispose: function(){
3485                 return (this.parentNode) ? this.parentNode.removeChild(this) : this;
3486         },
3487
3488         clone: function(contents, keepid){
3489                 contents = contents !== false;
3490                 var clone = this.cloneNode(contents), ce = [clone], te = [this], i;
3491
3492                 if (contents){
3493                         ce.append(Array.from(clone.getElementsByTagName('*')));
3494                         te.append(Array.from(this.getElementsByTagName('*')));
3495                 }
3496
3497                 for (i = ce.length; i--;){
3498                         var node = ce[i], element = te[i];
3499                         if (!keepid) node.removeAttribute('id');
3500                         /*<ltIE9>*/
3501                         if (node.clearAttributes){
3502                                 node.clearAttributes();
3503                                 node.mergeAttributes(element);
3504                                 node.removeAttribute('uniqueNumber');
3505                                 if (node.options){
3506                                         var no = node.options, eo = element.options;
3507                                         for (var j = no.length; j--;) no[j].selected = eo[j].selected;
3508                                 }
3509                         }
3510                         /*</ltIE9>*/
3511                         var prop = formProps[element.tagName.toLowerCase()];
3512                         if (prop && element[prop]) node[prop] = element[prop];
3513                 }
3514
3515                 /*<ltIE9>*/
3516                 if (Browser.ie){
3517                         var co = clone.getElementsByTagName('object'), to = this.getElementsByTagName('object');
3518                         for (i = co.length; i--;) co[i].outerHTML = to[i].outerHTML;
3519                 }
3520                 /*</ltIE9>*/
3521                 return document.id(clone);
3522         }
3523
3524 });
3525
3526 [Element, Window, Document].invoke('implement', {
3527
3528         addListener: function(type, fn){
3529                 if (type == 'unload'){
3530                         var old = fn, self = this;
3531                         fn = function(){
3532                                 self.removeListener('unload', fn);
3533                                 old();
3534                         };
3535                 } else {
3536                         collected[Slick.uidOf(this)] = this;
3537                 }
3538                 if (this.addEventListener) this.addEventListener(type, fn, !!arguments[2]);
3539                 else this.attachEvent('on' + type, fn);
3540                 return this;
3541         },
3542
3543         removeListener: function(type, fn){
3544                 if (this.removeEventListener) this.removeEventListener(type, fn, !!arguments[2]);
3545                 else this.detachEvent('on' + type, fn);
3546                 return this;
3547         },
3548
3549         retrieve: function(property, dflt){
3550                 var storage = get(Slick.uidOf(this)), prop = storage[property];
3551                 if (dflt != null && prop == null) prop = storage[property] = dflt;
3552                 return prop != null ? prop : null;
3553         },
3554
3555         store: function(property, value){
3556                 var storage = get(Slick.uidOf(this));
3557                 storage[property] = value;
3558                 return this;
3559         },
3560
3561         eliminate: function(property){
3562                 var storage = get(Slick.uidOf(this));
3563                 delete storage[property];
3564                 return this;
3565         }
3566
3567 });
3568
3569 /*<ltIE9>*/
3570 if (window.attachEvent && !window.addEventListener) window.addListener('unload', function(){
3571         Object.each(collected, clean);
3572         if (window.CollectGarbage) CollectGarbage();
3573 });
3574 /*</ltIE9>*/
3575
3576 Element.Properties = {};
3577
3578 //<1.2compat>
3579
3580 Element.Properties = new Hash;
3581
3582 //</1.2compat>
3583
3584 Element.Properties.style = {
3585
3586         set: function(style){
3587                 this.style.cssText = style;
3588         },
3589
3590         get: function(){
3591                 return this.style.cssText;
3592         },
3593
3594         erase: function(){
3595                 this.style.cssText = '';
3596         }
3597
3598 };
3599
3600 Element.Properties.tag = {
3601
3602         get: function(){
3603                 return this.tagName.toLowerCase();
3604         }
3605
3606 };
3607
3608 Element.Properties.html = {
3609
3610         set: function(html){
3611                 if (html == null) html = '';
3612                 else if (typeOf(html) == 'array') html = html.join('');
3613                 this.innerHTML = html;
3614         },
3615
3616         erase: function(){
3617                 this.innerHTML = '';
3618         }
3619
3620 };
3621
3622 /*<ltIE9>*/
3623 // technique by jdbarlett - http://jdbartlett.com/innershiv/
3624 var div = document.createElement('div');
3625 div.innerHTML = '<nav></nav>';
3626 var supportsHTML5Elements = (div.childNodes.length == 1);
3627 if (!supportsHTML5Elements){
3628         var tags = 'abbr article aside audio canvas datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video'.split(' '),
3629                 fragment = document.createDocumentFragment(), l = tags.length;
3630         while (l--) fragment.createElement(tags[l]);
3631 }
3632 div = null;
3633 /*</ltIE9>*/
3634
3635 /*<IE>*/
3636 var supportsTableInnerHTML = Function.attempt(function(){
3637         var table = document.createElement('table');
3638         table.innerHTML = '<tr><td></td></tr>';
3639         return true;
3640 });
3641
3642 /*<ltFF4>*/
3643 var tr = document.createElement('tr'), html = '<td></td>';
3644 tr.innerHTML = html;
3645 var supportsTRInnerHTML = (tr.innerHTML == html);
3646 tr = null;
3647 /*</ltFF4>*/
3648
3649 if (!supportsTableInnerHTML || !supportsTRInnerHTML || !supportsHTML5Elements){
3650
3651         Element.Properties.html.set = (function(set){
3652
3653                 var translations = {
3654                         table: [1, '<table>', '</table>'],
3655                         select: [1, '<select>', '</select>'],
3656                         tbody: [2, '<table><tbody>', '</tbody></table>'],
3657                         tr: [3, '<table><tbody><tr>', '</tr></tbody></table>']
3658                 };
3659
3660                 translations.thead = translations.tfoot = translations.tbody;
3661
3662                 return function(html){
3663                         var wrap = translations[this.get('tag')];
3664                         if (!wrap && !supportsHTML5Elements) wrap = [0, '', ''];
3665                         if (!wrap) return set.call(this, html);
3666
3667                         var level = wrap[0], wrapper = document.createElement('div'), target = wrapper;
3668                         if (!supportsHTML5Elements) fragment.appendChild(wrapper);
3669                         wrapper.innerHTML = [wrap[1], html, wrap[2]].flatten().join('');
3670                         while (level--) target = target.firstChild;
3671                         this.empty().adopt(target.childNodes);
3672                         if (!supportsHTML5Elements) fragment.removeChild(wrapper);
3673                         wrapper = null;
3674                 };
3675
3676         })(Element.Properties.html.set);
3677 }
3678 /*</IE>*/
3679
3680 /*<ltIE9>*/
3681 var testForm = document.createElement('form');
3682 testForm.innerHTML = '<select><option>s</option></select>';
3683
3684 if (testForm.firstChild.value != 's') Element.Properties.value = {
3685
3686         set: function(value){
3687                 var tag = this.get('tag');
3688                 if (tag != 'select') return this.setProperty('value', value);
3689                 var options = this.getElements('option');
3690                 for (var i = 0; i < options.length; i++){
3691                         var option = options[i],
3692                                 attr = option.getAttributeNode('value'),
3693                                 optionValue = (attr && attr.specified) ? option.value : option.get('text');
3694                         if (optionValue == value) return option.selected = true;
3695                 }
3696         },
3697
3698         get: function(){
3699                 var option = this, tag = option.get('tag');
3700
3701                 if (tag != 'select' && tag != 'option') return this.getProperty('value');
3702
3703                 if (tag == 'select' && !(option = option.getSelected()[0])) return '';
3704
3705                 var attr = option.getAttributeNode('value');
3706                 return (attr && attr.specified) ? option.value : option.get('text');
3707         }
3708
3709 };
3710 testForm = null;
3711 /*</ltIE9>*/
3712
3713 /*<IE>*/
3714 if (document.createElement('div').getAttributeNode('id')) Element.Properties.id = {
3715         set: function(id){
3716                 this.id = this.getAttributeNode('id').value = id;
3717         },
3718         get: function(){
3719                 return this.id || null;
3720         },
3721         erase: function(){
3722                 this.id = this.getAttributeNode('id').value = '';
3723         }
3724 };
3725 /*</IE>*/
3726
3727 })();
3728
3729
3730 // Begin: Source/Class/Class.js
3731 /*
3732 ---
3733
3734 name: Class
3735
3736 description: Contains the Class Function for easily creating, extending, and implementing reusable Classes.
3737
3738 license: MIT-style license.
3739
3740 requires: [Array, String, Function, Number]
3741
3742 provides: Class
3743
3744 ...
3745 */
3746
3747 (function(){
3748
3749 var Class = this.Class = new Type('Class', function(params){
3750         if (instanceOf(params, Function)) params = {initialize: params};
3751
3752         var newClass = function(){
3753                 reset(this);
3754                 if (newClass.$prototyping) return this;
3755                 this.$caller = null;
3756                 var value = (this.initialize) ? this.initialize.apply(this, arguments) : this;
3757                 this.$caller = this.caller = null;
3758                 return value;
3759         }.extend(this).implement(params);
3760
3761         newClass.$constructor = Class;
3762         newClass.prototype.$constructor = newClass;
3763         newClass.prototype.parent = parent;
3764
3765         return newClass;
3766 });
3767
3768 var parent = function(){
3769         if (!this.$caller) throw new Error('The method "parent" cannot be called.');
3770         var name = this.$caller.$name,
3771                 parent = this.$caller.$owner.parent,
3772                 previous = (parent) ? parent.prototype[name] : null;
3773         if (!previous) throw new Error('The method "' + name + '" has no parent.');
3774         return previous.apply(this, arguments);
3775 };
3776
3777 var reset = function(object){
3778         for (var key in object){
3779                 var value = object[key];
3780                 switch (typeOf(value)){
3781                         case 'object':
3782                                 var F = function(){};
3783                                 F.prototype = value;
3784                                 object[key] = reset(new F);
3785                         break;
3786                         case 'array': object[key] = value.clone(); break;
3787                 }
3788         }
3789         return object;
3790 };
3791
3792 var wrap = function(self, key, method){
3793         if (method.$origin) method = method.$origin;
3794         var wrapper = function(){
3795                 if (method.$protected && this.$caller == null) throw new Error('The method "' + key + '" cannot be called.');
3796                 var caller = this.caller, current = this.$caller;
3797                 this.caller = current; this.$caller = wrapper;
3798                 var result = method.apply(this, arguments);
3799                 this.$caller = current; this.caller = caller;
3800                 return result;
3801         }.extend({$owner: self, $origin: method, $name: key});
3802         return wrapper;
3803 };
3804
3805 var implement = function(key, value, retain){
3806         if (Class.Mutators.hasOwnProperty(key)){
3807                 value = Class.Mutators[key].call(this, value);
3808                 if (value == null) return this;
3809         }
3810
3811         if (typeOf(value) == 'function'){
3812                 if (value.$hidden) return this;
3813                 this.prototype[key] = (retain) ? value : wrap(this, key, value);
3814         } else {
3815                 Object.merge(this.prototype, key, value);
3816         }
3817
3818         return this;
3819 };
3820
3821 var getInstance = function(klass){
3822         klass.$prototyping = true;
3823         var proto = new klass;
3824         delete klass.$prototyping;
3825         return proto;
3826 };
3827
3828 Class.implement('implement', implement.overloadSetter());
3829
3830 Class.Mutators = {
3831
3832         Extends: function(parent){
3833                 this.parent = parent;
3834                 this.prototype = getInstance(parent);
3835         },
3836
3837         Implements: function(items){
3838                 Array.from(items).each(function(item){
3839                         var instance = new item;
3840                         for (var key in instance) implement.call(this, key, instance[key], true);
3841                 }, this);
3842         }
3843 };
3844
3845 })();
3846
3847
3848 // Begin: Source/Class/Class.Extras.js
3849 /*
3850 ---
3851
3852 name: Class.Extras
3853
3854 description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
3855
3856 license: MIT-style license.
3857
3858 requires: Class
3859
3860 provides: [Class.Extras, Chain, Events, Options]
3861
3862 ...
3863 */
3864
3865 (function(){
3866
3867 this.Chain = new Class({
3868
3869         $chain: [],
3870
3871         chain: function(){
3872                 this.$chain.append(Array.flatten(arguments));
3873                 return this;
3874         },
3875
3876         callChain: function(){
3877                 return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
3878         },
3879
3880         clearChain: function(){
3881                 this.$chain.empty();
3882                 return this;
3883         }
3884
3885 });
3886
3887 var removeOn = function(string){
3888         return string.replace(/^on([A-Z])/, function(full, first){
3889                 return first.toLowerCase();
3890         });
3891 };
3892
3893 this.Events = new Class({
3894
3895         $events: {},
3896
3897         addEvent: function(type, fn, internal){
3898                 type = removeOn(type);
3899
3900                 /*<1.2compat>*/
3901                 if (fn == $empty) return this;
3902                 /*</1.2compat>*/
3903
3904                 this.$events[type] = (this.$events[type] || []).include(fn);
3905                 if (internal) fn.internal = true;
3906                 return this;
3907         },
3908
3909         addEvents: function(events){
3910                 for (var type in events) this.addEvent(type, events[type]);
3911                 return this;
3912         },
3913
3914         fireEvent: function(type, args, delay){
3915                 type = removeOn(type);
3916                 var events = this.$events[type];
3917                 if (!events) return this;
3918                 args = Array.from(args);
3919                 events.each(function(fn){
3920                         if (delay) fn.delay(delay, this, args);
3921                         else fn.apply(this, args);
3922                 }, this);
3923                 return this;
3924         },
3925
3926         removeEvent: function(type, fn){
3927                 type = removeOn(type);
3928                 var events = this.$events[type];
3929                 if (events && !fn.internal){
3930                         var index =  events.indexOf(fn);
3931                         if (index != -1) delete events[index];
3932                 }
3933                 return this;
3934         },
3935
3936         removeEvents: function(events){
3937                 var type;
3938                 if (typeOf(events) == 'object'){
3939                         for (type in events) this.removeEvent(type, events[type]);
3940                         return this;
3941                 }
3942                 if (events) events = removeOn(events);
3943                 for (type in this.$events){
3944                         if (events && events != type) continue;
3945                         var fns = this.$events[type];
3946                         for (var i = fns.length; i--;) if (i in fns){
3947                                 this.removeEvent(type, fns[i]);
3948                         }
3949                 }
3950                 return this;
3951         }
3952
3953 });
3954
3955 this.Options = new Class({
3956
3957         setOptions: function(){
3958                 var options = this.options = Object.merge.apply(null, [{}, this.options].append(arguments));
3959                 if (this.addEvent) for (var option in options){
3960                         if (typeOf(options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
3961                         this.addEvent(option, options[option]);
3962                         delete options[option];
3963                 }
3964                 return this;
3965         }
3966
3967 });
3968
3969 })();
3970
3971
3972 // Begin: Source/Request/Request.js
3973 /*
3974 ---
3975
3976 name: Request
3977
3978 description: Powerful all purpose Request Class. Uses XMLHTTPRequest.
3979
3980 license: MIT-style license.
3981
3982 requires: [Object, Element, Chain, Events, Options, Browser]
3983
3984 provides: Request
3985
3986 ...
3987 */
3988
3989 (function(){
3990
3991 var empty = function(){},
3992         progressSupport = ('onprogress' in new Browser.Request);
3993
3994 var Request = this.Request = new Class({
3995
3996         Implements: [Chain, Events, Options],
3997
3998         options: {/*
3999                 onRequest: function(){},
4000                 onLoadstart: function(event, xhr){},
4001                 onProgress: function(event, xhr){},
4002                 onComplete: function(){},
4003                 onCancel: function(){},
4004                 onSuccess: function(responseText, responseXML){},
4005                 onFailure: function(xhr){},
4006                 onException: function(headerName, value){},
4007                 onTimeout: function(){},
4008                 user: '',
4009                 password: '',*/
4010                 url: '',
4011                 data: '',
4012                 headers: {
4013                         'X-Requested-With': 'XMLHttpRequest',
4014                         'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
4015                 },
4016                 async: true,
4017                 format: false,
4018                 method: 'post',
4019                 link: 'ignore',
4020                 isSuccess: null,
4021                 emulation: true,
4022                 urlEncoded: true,
4023                 encoding: 'utf-8',
4024                 evalScripts: false,
4025                 evalResponse: false,
4026                 timeout: 0,
4027                 noCache: false
4028         },
4029
4030         initialize: function(options){
4031                 this.xhr = new Browser.Request();
4032                 this.setOptions(options);
4033                 this.headers = this.options.headers;
4034         },
4035
4036         onStateChange: function(){
4037                 var xhr = this.xhr;
4038                 if (xhr.readyState != 4 || !this.running) return;
4039                 this.running = false;
4040                 this.status = 0;
4041                 Function.attempt(function(){
4042                         var status = xhr.status;
4043                         this.status = (status == 1223) ? 204 : status;
4044                 }.bind(this));
4045                 xhr.onreadystatechange = empty;
4046                 if (progressSupport) xhr.onprogress = xhr.onloadstart = empty;
4047                 clearTimeout(this.timer);
4048
4049                 this.response = {text: this.xhr.responseText || '', xml: this.xhr.responseXML};
4050                 if (this.options.isSuccess.call(this, this.status))
4051                         this.success(this.response.text, this.response.xml);
4052                 else
4053                         this.failure();
4054         },
4055
4056         isSuccess: function(){
4057                 var status = this.status;
4058                 return (status >= 200 && status < 300);
4059         },
4060
4061         isRunning: function(){
4062                 return !!this.running;
4063         },
4064
4065         processScripts: function(text){
4066                 if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return Browser.exec(text);
4067                 return text.stripScripts(this.options.evalScripts);
4068         },
4069
4070         success: function(text, xml){
4071                 this.onSuccess(this.processScripts(text), xml);
4072         },
4073
4074         onSuccess: function(){
4075                 this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain();
4076         },
4077
4078         failure: function(){
4079                 this.onFailure();
4080         },
4081
4082         onFailure: function(){
4083                 this.fireEvent('complete').fireEvent('failure', this.xhr);
4084         },
4085
4086         loadstart: function(event){
4087                 this.fireEvent('loadstart', [event, this.xhr]);
4088         },
4089
4090         progress: function(event){
4091                 this.fireEvent('progress', [event, this.xhr]);
4092         },
4093
4094         timeout: function(){
4095                 this.fireEvent('timeout', this.xhr);
4096         },
4097
4098         setHeader: function(name, value){
4099                 this.headers[name] = value;
4100                 return this;
4101         },
4102
4103         getHeader: function(name){
4104                 return Function.attempt(function(){
4105                         return this.xhr.getResponseHeader(name);
4106                 }.bind(this));
4107         },
4108
4109         check: function(){
4110                 if (!this.running) return true;
4111                 switch (this.options.link){
4112                         case 'cancel': this.cancel(); return true;
4113                         case 'chain': this.chain(this.caller.pass(arguments, this)); return false;
4114                 }
4115                 return false;
4116         },
4117
4118         send: function(options){
4119                 if (!this.check(options)) return this;
4120
4121                 this.options.isSuccess = this.options.isSuccess || this.isSuccess;
4122                 this.running = true;
4123
4124                 var type = typeOf(options);
4125                 if (type == 'string' || type == 'element') options = {data: options};
4126
4127                 var old = this.options;
4128                 options = Object.append({data: old.data, url: old.url, method: old.method}, options);
4129                 var data = options.data, url = String(options.url), method = options.method.toLowerCase();
4130
4131                 switch (typeOf(data)){
4132                         case 'element': data = document.id(data).toQueryString(); break;
4133                         case 'object': case 'hash': data = Object.toQueryString(data);
4134                 }
4135
4136                 if (this.options.format){
4137                         var format = 'format=' + this.options.format;
4138                         data = (data) ? format + '&' + data : format;
4139                 }
4140
4141                 if (this.options.emulation && !['get', 'post'].contains(method)){
4142                         var _method = '_method=' + method;
4143                         data = (data) ? _method + '&' + data : _method;
4144                         method = 'post';
4145                 }
4146
4147                 if (this.options.urlEncoded && ['post', 'put'].contains(method)){
4148                         var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
4149                         this.headers['Content-type'] = 'application/x-www-form-urlencoded' + encoding;
4150                 }
4151
4152                 if (!url) url = document.location.pathname;
4153
4154                 var trimPosition = url.lastIndexOf('/');
4155                 if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition);
4156
4157                 if (this.options.noCache)
4158                         url += (url.contains('?') ? '&' : '?') + String.uniqueID();
4159
4160                 if (data && method == 'get'){
4161                         url += (url.contains('?') ? '&' : '?') + data;
4162                         data = null;
4163                 }
4164
4165                 var xhr = this.xhr;
4166                 if (progressSupport){
4167                         xhr.onloadstart = this.loadstart.bind(this);
4168                         xhr.onprogress = this.progress.bind(this);
4169                 }
4170
4171                 xhr.open(method.toUpperCase(), url, this.options.async, this.options.user, this.options.password);
4172                 if (this.options.user && 'withCredentials' in xhr) xhr.withCredentials = true;
4173
4174                 xhr.onreadystatechange = this.onStateChange.bind(this);
4175
4176                 Object.each(this.headers, function(value, key){
4177                         try {
4178                                 xhr.setRequestHeader(key, value);
4179                         } catch (e){
4180                                 this.fireEvent('exception', [key, value]);
4181                         }
4182                 }, this);
4183
4184                 this.fireEvent('request');
4185                 xhr.send(data);
4186                 if (!this.options.async) this.onStateChange();
4187                 else if (this.options.timeout) this.timer = this.timeout.delay(this.options.timeout, this);
4188                 return this;
4189         },
4190
4191         cancel: function(){
4192                 if (!this.running) return this;
4193                 this.running = false;
4194                 var xhr = this.xhr;
4195                 xhr.abort();
4196                 clearTimeout(this.timer);
4197                 xhr.onreadystatechange = empty;
4198                 if (progressSupport) xhr.onprogress = xhr.onloadstart = empty;
4199                 this.xhr = new Browser.Request();
4200                 this.fireEvent('cancel');
4201                 return this;
4202         }
4203
4204 });
4205
4206 var methods = {};
4207 ['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){
4208         methods[method] = function(data){
4209                 var object = {
4210                         method: method
4211                 };
4212                 if (data != null) object.data = data;
4213                 return this.send(object);
4214         };
4215 });
4216
4217 Request.implement(methods);
4218
4219 Element.Properties.send = {
4220
4221         set: function(options){
4222                 var send = this.get('send').cancel();
4223                 send.setOptions(options);
4224                 return this;
4225         },
4226
4227         get: function(){
4228                 var send = this.retrieve('send');
4229                 if (!send){
4230                         send = new Request({
4231                                 data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action')
4232                         });
4233                         this.store('send', send);
4234                 }
4235                 return send;
4236         }
4237
4238 };
4239
4240 Element.implement({
4241
4242         send: function(url){
4243                 var sender = this.get('send');
4244                 sender.send({data: this, url: url || sender.options.url});
4245                 return this;
4246         }
4247
4248 });
4249
4250 })();
4251
4252
4253 // Begin: Source/Utilities/JSON.js
4254 /*
4255 ---
4256
4257 name: JSON
4258
4259 description: JSON encoder and decoder.
4260
4261 license: MIT-style license.
4262
4263 SeeAlso: <http://www.json.org/>
4264
4265 requires: [Array, String, Number, Function]
4266
4267 provides: JSON
4268
4269 ...
4270 */
4271
4272 if (typeof JSON == 'undefined') this.JSON = {};
4273
4274 //<1.2compat>
4275
4276 JSON = new Hash({
4277         stringify: JSON.stringify,
4278         parse: JSON.parse
4279 });
4280
4281 //</1.2compat>
4282
4283 (function(){
4284
4285 var special = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'};
4286
4287 var escape = function(chr){
4288         return special[chr] || '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4);
4289 };
4290
4291 JSON.validate = function(string){
4292         string = string.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
4293                                         replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
4294                                         replace(/(?:^|:|,)(?:\s*\[)+/g, '');
4295
4296         return (/^[\],:{}\s]*$/).test(string);
4297 };
4298
4299 JSON.encode = JSON.stringify ? function(obj){
4300         return JSON.stringify(obj);
4301 } : function(obj){
4302         if (obj && obj.toJSON) obj = obj.toJSON();
4303
4304         switch (typeOf(obj)){
4305                 case 'string':
4306                         return '"' + obj.replace(/[\x00-\x1f\\"]/g, escape) + '"';
4307                 case 'array':
4308                         return '[' + obj.map(JSON.encode).clean() + ']';
4309                 case 'object': case 'hash':
4310                         var string = [];
4311                         Object.each(obj, function(value, key){
4312                                 var json = JSON.encode(value);
4313                                 if (json) string.push(JSON.encode(key) + ':' + json);
4314                         });
4315                         return '{' + string + '}';
4316                 case 'number': case 'boolean': return '' + obj;
4317                 case 'null': return 'null';
4318         }
4319
4320         return null;
4321 };
4322
4323 JSON.decode = function(string, secure){
4324         if (!string || typeOf(string) != 'string') return null;
4325
4326         if (secure || JSON.secure){
4327                 if (JSON.parse) return JSON.parse(string);
4328                 if (!JSON.validate(string)) throw new Error('JSON could not decode the input; security is enabled and the value is not secure.');
4329         }
4330
4331         return eval('(' + string + ')');
4332 };
4333
4334 })();
4335
4336
4337 // Begin: Source/Request/Request.JSON.js
4338 /*
4339 ---
4340
4341 name: Request.JSON
4342
4343 description: Extends the basic Request Class with additional methods for sending and receiving JSON data.
4344
4345 license: MIT-style license.
4346
4347 requires: [Request, JSON]
4348
4349 provides: Request.JSON
4350
4351 ...
4352 */
4353
4354 Request.JSON = new Class({
4355
4356         Extends: Request,
4357
4358         options: {
4359                 /*onError: function(text, error){},*/
4360                 secure: true
4361         },
4362
4363         initialize: function(options){
4364                 this.parent(options);
4365                 Object.append(this.headers, {
4366                         'Accept': 'application/json',
4367                         'X-Request': 'JSON'
4368                 });
4369         },
4370
4371         success: function(text){
4372                 var json;
4373                 try {
4374                         json = this.response.json = JSON.decode(text, this.options.secure);
4375                 } catch (error){
4376                         this.fireEvent('error', [text, error]);
4377                         return;
4378                 }
4379                 if (json == null) this.onFailure();
4380                 else this.onSuccess(json, text);
4381         }
4382
4383 });
4384
4385
4386 // Begin: Source/Types/DOMEvent.js
4387 /*
4388 ---
4389
4390 name: Event
4391
4392 description: Contains the Event Type, to make the event object cross-browser.
4393
4394 license: MIT-style license.
4395
4396 requires: [Window, Document, Array, Function, String, Object]
4397
4398 provides: Event
4399
4400 ...
4401 */
4402
4403 (function() {
4404
4405 var _keys = {};
4406
4407 var DOMEvent = this.DOMEvent = new Type('DOMEvent', function(event, win){
4408         if (!win) win = window;
4409         event = event || win.event;
4410         if (event.$extended) return event;
4411         this.event = event;
4412         this.$extended = true;
4413         this.shift = event.shiftKey;
4414         this.control = event.ctrlKey;
4415         this.alt = event.altKey;
4416         this.meta = event.metaKey;
4417         var type = this.type = event.type;
4418         var target = event.target || event.srcElement;
4419         while (target && target.nodeType == 3) target = target.parentNode;
4420         this.target = document.id(target);
4421
4422         if (type.indexOf('key') == 0){
4423                 var code = this.code = (event.which || event.keyCode);
4424                 this.key = _keys[code]/*<1.3compat>*/ || Object.keyOf(Event.Keys, code)/*</1.3compat>*/;
4425                 if (type == 'keydown'){
4426                         if (code > 111 && code < 124) this.key = 'f' + (code - 111);
4427                         else if (code > 95 && code < 106) this.key = code - 96;
4428                 }
4429                 if (this.key == null) this.key = String.fromCharCode(code).toLowerCase();
4430         } else if (type == 'click' || type == 'dblclick' || type == 'contextmenu' || type == 'DOMMouseScroll' || type.indexOf('mouse') == 0){
4431                 var doc = win.document;
4432                 doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
4433                 this.page = {
4434                         x: (event.pageX != null) ? event.pageX : event.clientX + doc.scrollLeft,
4435                         y: (event.pageY != null) ? event.pageY : event.clientY + doc.scrollTop
4436                 };
4437                 this.client = {
4438                         x: (event.pageX != null) ? event.pageX - win.pageXOffset : event.clientX,
4439                         y: (event.pageY != null) ? event.pageY - win.pageYOffset : event.clientY
4440                 };
4441                 if (type == 'DOMMouseScroll' || type == 'mousewheel')
4442                         this.wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
4443
4444                 this.rightClick = (event.which == 3 || event.button == 2);
4445                 if (type == 'mouseover' || type == 'mouseout'){
4446                         var related = event.relatedTarget || event[(type == 'mouseover' ? 'from' : 'to') + 'Element'];
4447                         while (related && related.nodeType == 3) related = related.parentNode;
4448                         this.relatedTarget = document.id(related);
4449                 }
4450         } else if (type.indexOf('touch') == 0 || type.indexOf('gesture') == 0){
4451                 this.rotation = event.rotation;
4452                 this.scale = event.scale;
4453                 this.targetTouches = event.targetTouches;
4454                 this.changedTouches = event.changedTouches;
4455                 var touches = this.touches = event.touches;
4456                 if (touches && touches[0]){
4457                         var touch = touches[0];
4458                         this.page = {x: touch.pageX, y: touch.pageY};
4459                         this.client = {x: touch.clientX, y: touch.clientY};
4460                 }
4461         }
4462
4463         if (!this.client) this.client = {};
4464         if (!this.page) this.page = {};
4465 });
4466
4467 DOMEvent.implement({
4468
4469         stop: function(){
4470                 return this.preventDefault().stopPropagation();
4471         },
4472
4473         stopPropagation: function(){
4474                 if (this.event.stopPropagation) this.event.stopPropagation();
4475                 else this.event.cancelBubble = true;
4476                 return this;
4477         },
4478
4479         preventDefault: function(){
4480                 if (this.event.preventDefault) this.event.preventDefault();
4481                 else this.event.returnValue = false;
4482                 return this;
4483         }
4484
4485 });
4486
4487 DOMEvent.defineKey = function(code, key){
4488         _keys[code] = key;
4489         return this;
4490 };
4491
4492 DOMEvent.defineKeys = DOMEvent.defineKey.overloadSetter(true);
4493
4494 DOMEvent.defineKeys({
4495         '38': 'up', '40': 'down', '37': 'left', '39': 'right',
4496         '27': 'esc', '32': 'space', '8': 'backspace', '9': 'tab',
4497         '46': 'delete', '13': 'enter'
4498 });
4499
4500 })();
4501
4502 /*<1.3compat>*/
4503 var Event = DOMEvent;
4504 Event.Keys = {};
4505 /*</1.3compat>*/
4506
4507 /*<1.2compat>*/
4508
4509 Event.Keys = new Hash(Event.Keys);
4510
4511 /*</1.2compat>*/
4512
4513
4514 // Begin: Source/Element/Element.Event.js
4515 /*
4516 ---
4517
4518 name: Element.Event
4519
4520 description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events, if necessary.
4521
4522 license: MIT-style license.
4523
4524 requires: [Element, Event]
4525
4526 provides: Element.Event
4527
4528 ...
4529 */
4530
4531 (function(){
4532
4533 Element.Properties.events = {set: function(events){
4534         this.addEvents(events);
4535 }};
4536
4537 [Element, Window, Document].invoke('implement', {
4538
4539         addEvent: function(type, fn){
4540                 var events = this.retrieve('events', {});
4541                 if (!events[type]) events[type] = {keys: [], values: []};
4542                 if (events[type].keys.contains(fn)) return this;
4543                 events[type].keys.push(fn);
4544                 var realType = type,
4545                         custom = Element.Events[type],
4546                         condition = fn,
4547                         self = this;
4548                 if (custom){
4549                         if (custom.onAdd) custom.onAdd.call(this, fn, type);
4550                         if (custom.condition){
4551                                 condition = function(event){
4552                                         if (custom.condition.call(this, event, type)) return fn.call(this, event);
4553                                         return true;
4554                                 };
4555                         }
4556                         if (custom.base) realType = Function.from(custom.base).call(this, type);
4557                 }
4558                 var defn = function(){
4559                         return fn.call(self);
4560                 };
4561                 var nativeEvent = Element.NativeEvents[realType];
4562                 if (nativeEvent){
4563                         if (nativeEvent == 2){
4564                                 defn = function(event){
4565                                         event = new DOMEvent(event, self.getWindow());
4566                                         if (condition.call(self, event) === false) event.stop();
4567                                 };
4568                         }
4569                         this.addListener(realType, defn, arguments[2]);
4570                 }
4571                 events[type].values.push(defn);
4572                 return this;
4573         },
4574
4575         removeEvent: function(type, fn){
4576                 var events = this.retrieve('events');
4577                 if (!events || !events[type]) return this;
4578                 var list = events[type];
4579                 var index = list.keys.indexOf(fn);
4580                 if (index == -1) return this;
4581                 var value = list.values[index];
4582                 delete list.keys[index];
4583                 delete list.values[index];
4584                 var custom = Element.Events[type];
4585                 if (custom){
4586                         if (custom.onRemove) custom.onRemove.call(this, fn, type);
4587                         if (custom.base) type = Function.from(custom.base).call(this, type);
4588                 }
4589                 return (Element.NativeEvents[type]) ? this.removeListener(type, value, arguments[2]) : this;
4590         },
4591
4592         addEvents: function(events){
4593                 for (var event in events) this.addEvent(event, events[event]);
4594                 return this;
4595         },
4596
4597         removeEvents: function(events){
4598                 var type;
4599                 if (typeOf(events) == 'object'){
4600                         for (type in events) this.removeEvent(type, events[type]);
4601                         return this;
4602                 }
4603                 var attached = this.retrieve('events');
4604                 if (!attached) return this;
4605                 if (!events){
4606                         for (type in attached) this.removeEvents(type);
4607                         this.eliminate('events');
4608                 } else if (attached[events]){
4609                         attached[events].keys.each(function(fn){
4610                                 this.removeEvent(events, fn);
4611                         }, this);
4612                         delete attached[events];
4613                 }
4614                 return this;
4615         },
4616
4617         fireEvent: function(type, args, delay){
4618                 var events = this.retrieve('events');
4619                 if (!events || !events[type]) return this;
4620                 args = Array.from(args);
4621
4622                 events[type].keys.each(function(fn){
4623                         if (delay) fn.delay(delay, this, args);
4624                         else fn.apply(this, args);
4625                 }, this);
4626                 return this;
4627         },
4628
4629         cloneEvents: function(from, type){
4630                 from = document.id(from);
4631                 var events = from.retrieve('events');
4632                 if (!events) return this;
4633                 if (!type){
4634                         for (var eventType in events) this.cloneEvents(from, eventType);
4635                 } else if (events[type]){
4636                         events[type].keys.each(function(fn){
4637                                 this.addEvent(type, fn);
4638                         }, this);
4639                 }
4640                 return this;
4641         }
4642
4643 });
4644
4645 Element.NativeEvents = {
4646         click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons
4647         mousewheel: 2, DOMMouseScroll: 2, //mouse wheel
4648         mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement
4649         keydown: 2, keypress: 2, keyup: 2, //keyboard
4650         orientationchange: 2, // mobile
4651         touchstart: 2, touchmove: 2, touchend: 2, touchcancel: 2, // touch
4652         gesturestart: 2, gesturechange: 2, gestureend: 2, // gesture
4653         focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, paste: 2, input: 2, //form elements
4654         load: 2, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window
4655         error: 1, abort: 1, scroll: 1 //misc
4656 };
4657
4658 Element.Events = {mousewheel: {
4659         base: (Browser.firefox) ? 'DOMMouseScroll' : 'mousewheel'
4660 }};
4661
4662 if ('onmouseenter' in document.documentElement){
4663         Element.NativeEvents.mouseenter = Element.NativeEvents.mouseleave = 2;
4664 } else {
4665         var check = function(event){
4666                 var related = event.relatedTarget;
4667                 if (related == null) return true;
4668                 if (!related) return false;
4669                 return (related != this && related.prefix != 'xul' && typeOf(this) != 'document' && !this.contains(related));
4670         };
4671
4672         Element.Events.mouseenter = {
4673                 base: 'mouseover',
4674                 condition: check
4675         };
4676
4677         Element.Events.mouseleave = {
4678                 base: 'mouseout',
4679                 condition: check
4680         };
4681 }
4682
4683 /*<ltIE9>*/
4684 if (!window.addEventListener){
4685         Element.NativeEvents.propertychange = 2;
4686         Element.Events.change = {
4687                 base: function(){
4688                         var type = this.type;
4689                         return (this.get('tag') == 'input' && (type == 'radio' || type == 'checkbox')) ? 'propertychange' : 'change'
4690                 },
4691                 condition: function(event){
4692                         return this.type != 'radio' || (event.event.propertyName == 'checked' && this.checked);
4693                 }
4694         }
4695 }
4696 /*</ltIE9>*/
4697
4698 //<1.2compat>
4699
4700 Element.Events = new Hash(Element.Events);
4701
4702 //</1.2compat>
4703
4704 })();
4705
4706
4707 // Begin: Source/Element/Element.Delegation.js
4708 /*
4709 ---
4710
4711 name: Element.Delegation
4712
4713 description: Extends the Element native object to include the delegate method for more efficient event management.
4714
4715 license: MIT-style license.
4716
4717 requires: [Element.Event]
4718
4719 provides: [Element.Delegation]
4720
4721 ...
4722 */
4723
4724 (function(){
4725
4726 var eventListenerSupport = !!window.addEventListener;
4727
4728 Element.NativeEvents.focusin = Element.NativeEvents.focusout = 2;
4729
4730 var bubbleUp = function(self, match, fn, event, target){
4731         while (target && target != self){
4732                 if (match(target, event)) return fn.call(target, event, target);
4733                 target = document.id(target.parentNode);
4734         }
4735 };
4736
4737 var map = {
4738         mouseenter: {
4739                 base: 'mouseover'
4740         },
4741         mouseleave: {
4742                 base: 'mouseout'
4743         },
4744         focus: {
4745                 base: 'focus' + (eventListenerSupport ? '' : 'in'),
4746                 capture: true
4747         },
4748         blur: {
4749                 base: eventListenerSupport ? 'blur' : 'focusout',
4750                 capture: true
4751         }
4752 };
4753
4754 /*<ltIE9>*/
4755 var _key = '$delegation:';
4756 var formObserver = function(type){
4757
4758         return {
4759
4760                 base: 'focusin',
4761
4762                 remove: function(self, uid){
4763                         var list = self.retrieve(_key + type + 'listeners', {})[uid];
4764                         if (list && list.forms) for (var i = list.forms.length; i--;){
4765                                 list.forms[i].removeEvent(type, list.fns[i]);
4766                         }
4767                 },
4768
4769                 listen: function(self, match, fn, event, target, uid){
4770                         var form = (target.get('tag') == 'form') ? target : event.target.getParent('form');
4771                         if (!form) return;
4772
4773                         var listeners = self.retrieve(_key + type + 'listeners', {}),
4774                                 listener = listeners[uid] || {forms: [], fns: []},
4775                                 forms = listener.forms, fns = listener.fns;
4776
4777                         if (forms.indexOf(form) != -1) return;
4778                         forms.push(form);
4779
4780                         var _fn = function(event){
4781                                 bubbleUp(self, match, fn, event, target);
4782                         };
4783                         form.addEvent(type, _fn);
4784                         fns.push(_fn);
4785
4786                         listeners[uid] = listener;
4787                         self.store(_key + type + 'listeners', listeners);
4788                 }
4789         };
4790 };
4791
4792 var inputObserver = function(type){
4793         return {
4794                 base: 'focusin',
4795                 listen: function(self, match, fn, event, target){
4796                         var events = {blur: function(){
4797                                 this.removeEvents(events);
4798                         }};
4799                         events[type] = function(event){
4800                                 bubbleUp(self, match, fn, event, target);
4801                         };
4802                         event.target.addEvents(events);
4803                 }
4804         };
4805 };
4806
4807 if (!eventListenerSupport) Object.append(map, {
4808         submit: formObserver('submit'),
4809         reset: formObserver('reset'),
4810         change: inputObserver('change'),
4811         select: inputObserver('select')
4812 });
4813 /*</ltIE9>*/
4814
4815 var proto = Element.prototype,
4816         addEvent = proto.addEvent,
4817         removeEvent = proto.removeEvent;
4818
4819 var relay = function(old, method){
4820         return function(type, fn, useCapture){
4821                 if (type.indexOf(':relay') == -1) return old.call(this, type, fn, useCapture);
4822                 var parsed = Slick.parse(type).expressions[0][0];
4823                 if (parsed.pseudos[0].key != 'relay') return old.call(this, type, fn, useCapture);
4824                 var newType = parsed.tag;
4825                 parsed.pseudos.slice(1).each(function(pseudo){
4826                         newType += ':' + pseudo.key + (pseudo.value ? '(' + pseudo.value + ')' : '');
4827                 });
4828                 old.call(this, type, fn);
4829                 return method.call(this, newType, parsed.pseudos[0].value, fn);
4830         };
4831 };
4832
4833 var delegation = {
4834
4835         addEvent: function(type, match, fn){
4836                 var storage = this.retrieve('$delegates', {}), stored = storage[type];
4837                 if (stored) for (var _uid in stored){
4838                         if (stored[_uid].fn == fn && stored[_uid].match == match) return this;
4839                 }
4840
4841                 var _type = type, _match = match, _fn = fn, _map = map[type] || {};
4842                 type = _map.base || _type;
4843
4844                 match = function(target){
4845                         return Slick.match(target, _match);
4846                 };
4847
4848                 var elementEvent = Element.Events[_type];
4849                 if (elementEvent && elementEvent.condition){
4850                         var __match = match, condition = elementEvent.condition;
4851                         match = function(target, event){
4852                                 return __match(target, event) && condition.call(target, event, type);
4853                         };
4854                 }
4855
4856                 var self = this, uid = String.uniqueID();
4857                 var delegator = _map.listen ? function(event, target){
4858                         if (!target && event && event.target) target = event.target;
4859                         if (target) _map.listen(self, match, fn, event, target, uid);
4860                 } : function(event, target){
4861                         if (!target && event && event.target) target = event.target;
4862                         if (target) bubbleUp(self, match, fn, event, target);
4863                 };
4864
4865                 if (!stored) stored = {};
4866                 stored[uid] = {
4867                         match: _match,
4868                         fn: _fn,
4869                         delegator: delegator
4870                 };
4871                 storage[_type] = stored;
4872                 return addEvent.call(this, type, delegator, _map.capture);
4873         },
4874
4875         removeEvent: function(type, match, fn, _uid){
4876                 var storage = this.retrieve('$delegates', {}), stored = storage[type];
4877                 if (!stored) return this;
4878
4879                 if (_uid){
4880                         var _type = type, delegator = stored[_uid].delegator, _map = map[type] || {};
4881                         type = _map.base || _type;
4882                         if (_map.remove) _map.remove(this, _uid);
4883                         delete stored[_uid];
4884                         storage[_type] = stored;
4885                         return removeEvent.call(this, type, delegator);
4886                 }
4887
4888                 var __uid, s;
4889                 if (fn) for (__uid in stored){
4890                         s = stored[__uid];
4891                         if (s.match == match && s.fn == fn) return delegation.removeEvent.call(this, type, match, fn, __uid);
4892                 } else for (__uid in stored){
4893                         s = stored[__uid];
4894                         if (s.match == match) delegation.removeEvent.call(this, type, match, s.fn, __uid);
4895                 }
4896                 return this;
4897         }
4898
4899 };
4900
4901 [Element, Window, Document].invoke('implement', {
4902         addEvent: relay(addEvent, delegation.addEvent),
4903         removeEvent: relay(removeEvent, delegation.removeEvent)
4904 });
4905
4906 })();
4907
4908
4909 // Begin: Source/Fx/Fx.js
4910 /*
4911 ---
4912
4913 name: Fx
4914
4915 description: Contains the basic animation logic to be extended by all other Fx Classes.
4916
4917 license: MIT-style license.
4918
4919 requires: [Chain, Events, Options]
4920
4921 provides: Fx
4922
4923 ...
4924 */
4925
4926 (function(){
4927
4928 var Fx = this.Fx = new Class({
4929
4930         Implements: [Chain, Events, Options],
4931
4932         options: {
4933                 /*
4934                 onStart: nil,
4935                 onCancel: nil,
4936                 onComplete: nil,
4937                 */
4938                 fps: 60,
4939                 unit: false,
4940                 duration: 500,
4941                 frames: null,
4942                 frameSkip: true,
4943                 link: 'ignore'
4944         },
4945
4946         initialize: function(options){
4947                 this.subject = this.subject || this;
4948                 this.setOptions(options);
4949         },
4950
4951         getTransition: function(){
4952                 return function(p){
4953                         return -(Math.cos(Math.PI * p) - 1) / 2;
4954                 };
4955         },
4956
4957         step: function(now){
4958                 if (this.options.frameSkip){
4959                         var diff = (this.time != null) ? (now - this.time) : 0, frames = diff / this.frameInterval;
4960                         this.time = now;
4961                         this.frame += frames;
4962                 } else {
4963                         this.frame++;
4964                 }
4965
4966                 if (this.frame < this.frames){
4967                         var delta = this.transition(this.frame / this.frames);
4968                         this.set(this.compute(this.from, this.to, delta));
4969                 } else {
4970                         this.frame = this.frames;
4971                         this.set(this.compute(this.from, this.to, 1));
4972                         this.stop();
4973                 }
4974         },
4975
4976         set: function(now){
4977                 return now;
4978         },
4979
4980         compute: function(from, to, delta){
4981                 return Fx.compute(from, to, delta);
4982         },
4983
4984         check: function(){
4985                 if (!this.isRunning()) return true;
4986                 switch (this.options.link){
4987                         case 'cancel': this.cancel(); return true;
4988                         case 'chain': this.chain(this.caller.pass(arguments, this)); return false;
4989                 }
4990                 return false;
4991         },
4992
4993         start: function(from, to){
4994                 if (!this.check(from, to)) return this;
4995                 this.from = from;
4996                 this.to = to;
4997                 this.frame = (this.options.frameSkip) ? 0 : -1;
4998                 this.time = null;
4999                 this.transition = this.getTransition();
5000                 var frames = this.options.frames, fps = this.options.fps, duration = this.options.duration;
5001                 this.duration = Fx.Durations[duration] || duration.toInt();
5002                 this.frameInterval = 1000 / fps;
5003                 this.frames = frames || Math.round(this.duration / this.frameInterval);
5004                 this.fireEvent('start', this.subject);
5005                 pushInstance.call(this, fps);
5006                 return this;
5007         },
5008
5009         stop: function(){
5010                 if (this.isRunning()){
5011                         this.time = null;
5012                         pullInstance.call(this, this.options.fps);
5013                         if (this.frames == this.frame){
5014                                 this.fireEvent('complete', this.subject);
5015                                 if (!this.callChain()) this.fireEvent('chainComplete', this.subject);
5016                         } else {
5017                                 this.fireEvent('stop', this.subject);
5018                         }
5019                 }
5020                 return this;
5021         },
5022
5023         cancel: function(){
5024                 if (this.isRunning()){
5025                         this.time = null;
5026                         pullInstance.call(this, this.options.fps);
5027                         this.frame = this.frames;
5028                         this.fireEvent('cancel', this.subject).clearChain();
5029                 }
5030                 return this;
5031         },
5032
5033         pause: function(){
5034                 if (this.isRunning()){
5035                         this.time = null;
5036                         pullInstance.call(this, this.options.fps);
5037                 }
5038                 return this;
5039         },
5040
5041         resume: function(){
5042                 if ((this.frame < this.frames) && !this.isRunning()) pushInstance.call(this, this.options.fps);
5043                 return this;
5044         },
5045
5046         isRunning: function(){
5047                 var list = instances[this.options.fps];
5048                 return list && list.contains(this);
5049         }
5050
5051 });
5052
5053 Fx.compute = function(from, to, delta){
5054         return (to - from) * delta + from;
5055 };
5056
5057 Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000};
5058
5059 // global timers
5060
5061 var instances = {}, timers = {};
5062
5063 var loop = function(){
5064         var now = Date.now();
5065         for (var i = this.length; i--;){
5066                 var instance = this[i];
5067                 if (instance) instance.step(now);
5068         }
5069 };
5070
5071 var pushInstance = function(fps){
5072         var list = instances[fps] || (instances[fps] = []);
5073         list.push(this);
5074         if (!timers[fps]) timers[fps] = loop.periodical(Math.round(1000 / fps), list);
5075 };
5076
5077 var pullInstance = function(fps){
5078         var list = instances[fps];
5079         if (list){
5080                 list.erase(this);
5081                 if (!list.length && timers[fps]){
5082                         delete instances[fps];
5083                         timers[fps] = clearInterval(timers[fps]);
5084                 }
5085         }
5086 };
5087
5088 })();
5089
5090
5091 // Begin: Source/Element/Element.Style.js
5092 /*
5093 ---
5094
5095 name: Element.Style
5096
5097 description: Contains methods for interacting with the styles of Elements in a fashionable way.
5098
5099 license: MIT-style license.
5100
5101 requires: Element
5102
5103 provides: Element.Style
5104
5105 ...
5106 */
5107
5108 (function(){
5109
5110 var html = document.html;
5111
5112 //<ltIE9>
5113 // Check for oldIE, which does not remove styles when they're set to null
5114 var el = document.createElement('div');
5115 el.style.color = 'red';
5116 el.style.color = null;
5117 var doesNotRemoveStyles = el.style.color == 'red';
5118 el = null;
5119 //</ltIE9>
5120
5121 Element.Properties.styles = {set: function(styles){
5122         this.setStyles(styles);
5123 }};
5124
5125 var hasOpacity = (html.style.opacity != null),
5126         hasFilter = (html.style.filter != null),
5127         reAlpha = /alpha\(opacity=([\d.]+)\)/i;
5128
5129 var setVisibility = function(element, opacity){
5130         element.store('$opacity', opacity);
5131         element.style.visibility = opacity > 0 || opacity == null ? 'visible' : 'hidden';
5132 };
5133
5134 var setOpacity = (hasOpacity ? function(element, opacity){
5135         element.style.opacity = opacity;
5136 } : (hasFilter ? function(element, opacity){
5137         var style = element.style;
5138         if (!element.currentStyle || !element.currentStyle.hasLayout) style.zoom = 1;
5139         if (opacity == null || opacity == 1) opacity = '';
5140         else opacity = 'alpha(opacity=' + (opacity * 100).limit(0, 100).round() + ')';
5141         var filter = style.filter || element.getComputedStyle('filter') || '';
5142         style.filter = reAlpha.test(filter) ? filter.replace(reAlpha, opacity) : filter + opacity;
5143         if (!style.filter) style.removeAttribute('filter');
5144 } : setVisibility));
5145
5146 var getOpacity = (hasOpacity ? function(element){
5147         var opacity = element.style.opacity || element.getComputedStyle('opacity');
5148         return (opacity == '') ? 1 : opacity.toFloat();
5149 } : (hasFilter ? function(element){
5150         var filter = (element.style.filter || element.getComputedStyle('filter')),
5151                 opacity;
5152         if (filter) opacity = filter.match(reAlpha);
5153         return (opacity == null || filter == null) ? 1 : (opacity[1] / 100);
5154 } : function(element){
5155         var opacity = element.retrieve('$opacity');
5156         if (opacity == null) opacity = (element.style.visibility == 'hidden' ? 0 : 1);
5157         return opacity;
5158 }));
5159
5160 var floatName = (html.style.cssFloat == null) ? 'styleFloat' : 'cssFloat';
5161
5162 Element.implement({
5163
5164         getComputedStyle: function(property){
5165                 if (this.currentStyle) return this.currentStyle[property.camelCase()];
5166                 var defaultView = Element.getDocument(this).defaultView,
5167                         computed = defaultView ? defaultView.getComputedStyle(this, null) : null;
5168                 return (computed) ? computed.getPropertyValue((property == floatName) ? 'float' : property.hyphenate()) : null;
5169         },
5170
5171         setStyle: function(property, value){
5172                 if (property == 'opacity'){
5173                         if (value != null) value = parseFloat(value);
5174                         setOpacity(this, value);
5175                         return this;
5176                 }
5177                 property = (property == 'float' ? floatName : property).camelCase();
5178                 if (typeOf(value) != 'string'){
5179                         var map = (Element.Styles[property] || '@').split(' ');
5180                         value = Array.from(value).map(function(val, i){
5181                                 if (!map[i]) return '';
5182                                 return (typeOf(val) == 'number') ? map[i].replace('@', Math.round(val)) : val;
5183                         }).join(' ');
5184                 } else if (value == String(Number(value))){
5185                         value = Math.round(value);
5186                 }
5187                 this.style[property] = value;
5188                 //<ltIE9>
5189                 if ((value == '' || value == null) && doesNotRemoveStyles && this.style.removeAttribute){
5190                         this.style.removeAttribute(property);
5191                 }
5192                 //</ltIE9>
5193                 return this;
5194         },
5195
5196         getStyle: function(property){
5197                 if (property == 'opacity') return getOpacity(this);
5198                 property = (property == 'float' ? floatName : property).camelCase();
5199                 var result = this.style[property];
5200                 if (!result || property == 'zIndex'){
5201                         result = [];
5202                         for (var style in Element.ShortStyles){
5203                                 if (property != style) continue;
5204                                 for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s));
5205                                 return result.join(' ');
5206                         }
5207                         result = this.getComputedStyle(property);
5208                 }
5209                 if (result){
5210                         result = String(result);
5211                         var color = result.match(/rgba?\([\d\s,]+\)/);
5212                         if (color) result = result.replace(color[0], color[0].rgbToHex());
5213                 }
5214                 if (Browser.opera || Browser.ie){
5215                         if ((/^(height|width)$/).test(property) && !(/px$/.test(result))){
5216                                 var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
5217                                 values.each(function(value){
5218                                         size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt();
5219                                 }, this);
5220                                 return this['offset' + property.capitalize()] - size + 'px';
5221                         }
5222                         if (Browser.ie && (/^border(.+)Width|margin|padding/).test(property) && isNaN(parseFloat(result))){
5223                                 return '0px';
5224                         }
5225                 }
5226                 return result;
5227         },
5228
5229         setStyles: function(styles){
5230                 for (var style in styles) this.setStyle(style, styles[style]);
5231                 return this;
5232         },
5233
5234         getStyles: function(){
5235                 var result = {};
5236                 Array.flatten(arguments).each(function(key){
5237                         result[key] = this.getStyle(key);
5238                 }, this);
5239                 return result;
5240         }
5241
5242 });
5243
5244 Element.Styles = {
5245         left: '@px', top: '@px', bottom: '@px', right: '@px',
5246         width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px',
5247         backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
5248         fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)',
5249         margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
5250         borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
5251         zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@'
5252 };
5253
5254 //<1.3compat>
5255
5256 Element.implement({
5257
5258         setOpacity: function(value){
5259                 setOpacity(this, value);
5260                 return this;
5261         },
5262
5263         getOpacity: function(){
5264                 return getOpacity(this);
5265         }
5266
5267 });
5268
5269 Element.Properties.opacity = {
5270
5271         set: function(opacity){
5272                 setOpacity(this, opacity);
5273                 setVisibility(this, opacity);
5274         },
5275
5276         get: function(){
5277                 return getOpacity(this);
5278         }
5279
5280 };
5281
5282 //</1.3compat>
5283
5284 //<1.2compat>
5285
5286 Element.Styles = new Hash(Element.Styles);
5287
5288 //</1.2compat>
5289
5290 Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}};
5291
5292 ['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
5293         var Short = Element.ShortStyles;
5294         var All = Element.Styles;
5295         ['margin', 'padding'].each(function(style){
5296                 var sd = style + direction;
5297                 Short[style][sd] = All[sd] = '@px';
5298         });
5299         var bd = 'border' + direction;
5300         Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)';
5301         var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color';
5302         Short[bd] = {};
5303         Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px';
5304         Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@';
5305         Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)';
5306 });
5307
5308 })();
5309
5310
5311 // Begin: Source/Fx/Fx.CSS.js
5312 /*
5313 ---
5314
5315 name: Fx.CSS
5316
5317 description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements.
5318
5319 license: MIT-style license.
5320
5321 requires: [Fx, Element.Style]
5322
5323 provides: Fx.CSS
5324
5325 ...
5326 */
5327
5328 Fx.CSS = new Class({
5329
5330         Extends: Fx,
5331
5332         //prepares the base from/to object
5333
5334         prepare: function(element, property, values){
5335                 values = Array.from(values);
5336                 var from = values[0], to = values[1];
5337                 if (to == null){
5338                         to = from;
5339                         from = element.getStyle(property);
5340                         var unit = this.options.unit;
5341                         // adapted from: https://github.com/ryanmorr/fx/blob/master/fx.js#L299
5342                         if (unit && from.slice(-unit.length) != unit && parseFloat(from) != 0){
5343                                 element.setStyle(property, to + unit);
5344                                 var value = element.getComputedStyle(property);
5345                                 // IE and Opera support pixelLeft or pixelWidth
5346                                 if (!(/px$/.test(value))){
5347                                         value = element.style[('pixel-' + property).camelCase()];
5348                                         if (value == null){
5349                                                 // adapted from Dean Edwards' http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
5350                                                 var left = element.style.left;
5351                                                 element.style.left = to + unit;
5352                                                 value = element.style.pixelLeft;
5353                                                 element.style.left = left;
5354                                         }
5355                                 }
5356                                 from = (to || 1) / (parseFloat(value) || 1) * (parseFloat(from) || 0);
5357                                 element.setStyle(property, from + unit);
5358                         }
5359                 }
5360                 return {from: this.parse(from), to: this.parse(to)};
5361         },
5362
5363         //parses a value into an array
5364
5365         parse: function(value){
5366                 value = Function.from(value)();
5367                 value = (typeof value == 'string') ? value.split(' ') : Array.from(value);
5368                 return value.map(function(val){
5369                         val = String(val);
5370                         var found = false;
5371                         Object.each(Fx.CSS.Parsers, function(parser, key){
5372                                 if (found) return;
5373                                 var parsed = parser.parse(val);
5374                                 if (parsed || parsed === 0) found = {value: parsed, parser: parser};
5375                         });
5376                         found = found || {value: val, parser: Fx.CSS.Parsers.String};
5377                         return found;
5378                 });
5379         },
5380
5381         //computes by a from and to prepared objects, using their parsers.
5382
5383         compute: function(from, to, delta){
5384                 var computed = [];
5385                 (Math.min(from.length, to.length)).times(function(i){
5386                         computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser});
5387                 });
5388                 computed.$family = Function.from('fx:css:value');
5389                 return computed;
5390         },
5391
5392         //serves the value as settable
5393
5394         serve: function(value, unit){
5395                 if (typeOf(value) != 'fx:css:value') value = this.parse(value);
5396                 var returned = [];
5397                 value.each(function(bit){
5398                         returned = returned.concat(bit.parser.serve(bit.value, unit));
5399                 });
5400                 return returned;
5401         },
5402
5403         //renders the change to an element
5404
5405         render: function(element, property, value, unit){
5406                 element.setStyle(property, this.serve(value, unit));
5407         },
5408
5409         //searches inside the page css to find the values for a selector
5410
5411         search: function(selector){
5412                 if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector];
5413                 var to = {}, selectorTest = new RegExp('^' + selector.escapeRegExp() + '$');
5414                 Array.each(document.styleSheets, function(sheet, j){
5415                         var href = sheet.href;
5416                         if (href && href.contains('://') && !href.contains(document.domain)) return;
5417                         var rules = sheet.rules || sheet.cssRules;
5418                         Array.each(rules, function(rule, i){
5419                                 if (!rule.style) return;
5420                                 var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){
5421                                         return m.toLowerCase();
5422                                 }) : null;
5423                                 if (!selectorText || !selectorTest.test(selectorText)) return;
5424                                 Object.each(Element.Styles, function(value, style){
5425                                         if (!rule.style[style] || Element.ShortStyles[style]) return;
5426                                         value = String(rule.style[style]);
5427                                         to[style] = ((/^rgb/).test(value)) ? value.rgbToHex() : value;
5428                                 });
5429                         });
5430                 });
5431                 return Fx.CSS.Cache[selector] = to;
5432         }
5433
5434 });
5435
5436 Fx.CSS.Cache = {};
5437
5438 Fx.CSS.Parsers = {
5439
5440         Color: {
5441                 parse: function(value){
5442                         if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true);
5443                         return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false;
5444                 },
5445                 compute: function(from, to, delta){
5446                         return from.map(function(value, i){
5447                                 return Math.round(Fx.compute(from[i], to[i], delta));
5448                         });
5449                 },
5450                 serve: function(value){
5451                         return value.map(Number);
5452                 }
5453         },
5454
5455         Number: {
5456                 parse: parseFloat,
5457                 compute: Fx.compute,
5458                 serve: function(value, unit){
5459                         return (unit) ? value + unit : value;
5460                 }
5461         },
5462
5463         String: {
5464                 parse: Function.from(false),
5465                 compute: function(zero, one){
5466                         return one;
5467                 },
5468                 serve: function(zero){
5469                         return zero;
5470                 }
5471         }
5472
5473 };
5474
5475 //<1.2compat>
5476
5477 Fx.CSS.Parsers = new Hash(Fx.CSS.Parsers);
5478
5479 //</1.2compat>
5480
5481
5482 // Begin: Source/Fx/Fx.Morph.js
5483 /*
5484 ---
5485
5486 name: Fx.Morph
5487
5488 description: Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules.
5489
5490 license: MIT-style license.
5491
5492 requires: Fx.CSS
5493
5494 provides: Fx.Morph
5495
5496 ...
5497 */
5498
5499 Fx.Morph = new Class({
5500
5501         Extends: Fx.CSS,
5502
5503         initialize: function(element, options){
5504                 this.element = this.subject = document.id(element);
5505                 this.parent(options);
5506         },
5507
5508         set: function(now){
5509                 if (typeof now == 'string') now = this.search(now);
5510                 for (var p in now) this.render(this.element, p, now[p], this.options.unit);
5511                 return this;
5512         },
5513
5514         compute: function(from, to, delta){
5515                 var now = {};
5516                 for (var p in from) now[p] = this.parent(from[p], to[p], delta);
5517                 return now;
5518         },
5519
5520         start: function(properties){
5521                 if (!this.check(properties)) return this;
5522                 if (typeof properties == 'string') properties = this.search(properties);
5523                 var from = {}, to = {};
5524                 for (var p in properties){
5525                         var parsed = this.prepare(this.element, p, properties[p]);
5526                         from[p] = parsed.from;
5527                         to[p] = parsed.to;
5528                 }
5529                 return this.parent(from, to);
5530         }
5531
5532 });
5533
5534 Element.Properties.morph = {
5535
5536         set: function(options){
5537                 this.get('morph').cancel().setOptions(options);
5538                 return this;
5539         },
5540
5541         get: function(){
5542                 var morph = this.retrieve('morph');
5543                 if (!morph){
5544                         morph = new Fx.Morph(this, {link: 'cancel'});
5545                         this.store('morph', morph);
5546                 }
5547                 return morph;
5548         }
5549
5550 };
5551
5552 Element.implement({
5553
5554         morph: function(props){
5555                 this.get('morph').start(props);
5556                 return this;
5557         }
5558
5559 });
5560
5561
5562 // Begin: Source/Utilities/Swiff.js
5563 /*
5564 ---
5565
5566 name: Swiff
5567
5568 description: Wrapper for embedding SWF movies. Supports External Interface Communication.
5569
5570 license: MIT-style license.
5571
5572 credits:
5573   - Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject.
5574
5575 requires: [Options, Object, Element]
5576
5577 provides: Swiff
5578
5579 ...
5580 */
5581
5582 (function(){
5583
5584 var Swiff = this.Swiff = new Class({
5585
5586         Implements: Options,
5587
5588         options: {
5589                 id: null,
5590                 height: 1,
5591                 width: 1,
5592                 container: null,
5593                 properties: {},
5594                 params: {
5595                         quality: 'high',
5596                         allowScriptAccess: 'always',
5597                         wMode: 'window',
5598                         swLiveConnect: true
5599                 },
5600                 callBacks: {},
5601                 vars: {}
5602         },
5603
5604         toElement: function(){
5605                 return this.object;
5606         },
5607
5608         initialize: function(path, options){
5609                 this.instance = 'Swiff_' + String.uniqueID();
5610
5611                 this.setOptions(options);
5612                 options = this.options;
5613                 var id = this.id = options.id || this.instance;
5614                 var container = document.id(options.container);
5615
5616                 Swiff.CallBacks[this.instance] = {};
5617
5618                 var params = options.params, vars = options.vars, callBacks = options.callBacks;
5619                 var properties = Object.append({height: options.height, width: options.width}, options.properties);
5620
5621                 var self = this;
5622
5623                 for (var callBack in callBacks){
5624                         Swiff.CallBacks[this.instance][callBack] = (function(option){
5625                                 return function(){
5626                                         return option.apply(self.object, arguments);
5627                                 };
5628                         })(callBacks[callBack]);
5629                         vars[callBack] = 'Swiff.CallBacks.' + this.instance + '.' + callBack;
5630                 }
5631
5632                 params.flashVars = Object.toQueryString(vars);
5633                 if (Browser.ie){
5634                         properties.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
5635                         params.movie = path;
5636                 } else {
5637                         properties.type = 'application/x-shockwave-flash';
5638                 }
5639                 properties.data = path;
5640
5641                 var build = '<object id="' + id + '"';
5642                 for (var property in properties) build += ' ' + property + '="' + properties[property] + '"';
5643                 build += '>';
5644                 for (var param in params){
5645                         if (params[param]) build += '<param name="' + param + '" value="' + params[param] + '" />';
5646                 }
5647                 build += '</object>';
5648                 this.object = ((container) ? container.empty() : new Element('div')).set('html', build).firstChild;
5649         },
5650
5651         replaces: function(element){
5652                 element = document.id(element, true);
5653                 element.parentNode.replaceChild(this.toElement(), element);
5654                 return this;
5655         },
5656
5657         inject: function(element){
5658                 document.id(element, true).appendChild(this.toElement());
5659                 return this;
5660         },
5661
5662         remote: function(){
5663                 return Swiff.remote.apply(Swiff, [this.toElement()].append(arguments));
5664         }
5665
5666 });
5667
5668 Swiff.CallBacks = {};
5669
5670 Swiff.remote = function(obj, fn){
5671         var rs = obj.CallFunction('<invoke name="' + fn + '" returntype="javascript">' + __flash__argumentsToXML(arguments, 2) + '</invoke>');
5672         return eval(rs);
5673 };
5674
5675 })();
5676
5677
5678 // Begin: Source/Fx/Fx.Transitions.js
5679 /*
5680 ---
5681
5682 name: Fx.Transitions
5683
5684 description: Contains a set of advanced transitions to be used with any of the Fx Classes.
5685
5686 license: MIT-style license.
5687
5688 credits:
5689   - Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools.
5690
5691 requires: Fx
5692
5693 provides: Fx.Transitions
5694
5695 ...
5696 */
5697
5698 Fx.implement({
5699
5700         getTransition: function(){
5701                 var trans = this.options.transition || Fx.Transitions.Sine.easeInOut;
5702                 if (typeof trans == 'string'){
5703                         var data = trans.split(':');
5704                         trans = Fx.Transitions;
5705                         trans = trans[data[0]] || trans[data[0].capitalize()];
5706                         if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')];
5707                 }
5708                 return trans;
5709         }
5710
5711 });
5712
5713 Fx.Transition = function(transition, params){
5714         params = Array.from(params);
5715         var easeIn = function(pos){
5716                 return transition(pos, params);
5717         };
5718         return Object.append(easeIn, {
5719                 easeIn: easeIn,
5720                 easeOut: function(pos){
5721                         return 1 - transition(1 - pos, params);
5722                 },
5723                 easeInOut: function(pos){
5724                         return (pos <= 0.5 ? transition(2 * pos, params) : (2 - transition(2 * (1 - pos), params))) / 2;
5725                 }
5726         });
5727 };
5728
5729 Fx.Transitions = {
5730
5731         linear: function(zero){
5732                 return zero;
5733         }
5734
5735 };
5736
5737 //<1.2compat>
5738
5739 Fx.Transitions = new Hash(Fx.Transitions);
5740
5741 //</1.2compat>
5742
5743 Fx.Transitions.extend = function(transitions){
5744         for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
5745 };
5746
5747 Fx.Transitions.extend({
5748
5749         Pow: function(p, x){
5750                 return Math.pow(p, x && x[0] || 6);
5751         },
5752
5753         Expo: function(p){
5754                 return Math.pow(2, 8 * (p - 1));
5755         },
5756
5757         Circ: function(p){
5758                 return 1 - Math.sin(Math.acos(p));
5759         },
5760
5761         Sine: function(p){
5762                 return 1 - Math.cos(p * Math.PI / 2);
5763         },
5764
5765         Back: function(p, x){
5766                 x = x && x[0] || 1.618;
5767                 return Math.pow(p, 2) * ((x + 1) * p - x);
5768         },
5769
5770         Bounce: function(p){
5771                 var value;
5772                 for (var a = 0, b = 1; 1; a += b, b /= 2){
5773                         if (p >= (7 - 4 * a) / 11){
5774                                 value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2);
5775                                 break;
5776                         }
5777                 }
5778                 return value;
5779         },
5780
5781         Elastic: function(p, x){
5782                 return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x && x[0] || 1) / 3);
5783         }
5784
5785 });
5786
5787 ['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
5788         Fx.Transitions[transition] = new Fx.Transition(function(p){
5789                 return Math.pow(p, i + 2);
5790         });
5791 });
5792
5793
5794 // Begin: Source/More/More.js
5795 /*
5796 ---
5797
5798 script: More.js
5799
5800 name: More
5801
5802 description: MooTools More
5803
5804 license: MIT-style license
5805
5806 authors:
5807   - Guillermo Rauch
5808   - Thomas Aylott
5809   - Scott Kyle
5810   - Arian Stolwijk
5811   - Tim Wienk
5812   - Christoph Pojer
5813   - Aaron Newton
5814   - Jacob Thornton
5815
5816 requires:
5817   - Core/MooTools
5818
5819 provides: [MooTools.More]
5820
5821 ...
5822 */
5823
5824 MooTools.More = {
5825         version: '1.4.3.1dev',
5826         build: '%build%'
5827 };
5828
5829
5830 // Begin: Source/Class/Class.Binds.js
5831 /*
5832 ---
5833
5834 script: Class.Binds.js
5835
5836 name: Class.Binds
5837
5838 description: Automagically binds specified methods in a class to the instance of the class.
5839
5840 license: MIT-style license
5841
5842 authors:
5843   - Aaron Newton
5844
5845 requires:
5846   - Core/Class
5847   - /MooTools.More
5848
5849 provides: [Class.Binds]
5850
5851 ...
5852 */
5853
5854 Class.Mutators.Binds = function(binds){
5855         if (!this.prototype.initialize) this.implement('initialize', function(){});
5856         return Array.from(binds).concat(this.prototype.Binds || []);
5857 };
5858
5859 Class.Mutators.initialize = function(initialize){
5860         return function(){
5861                 Array.from(this.Binds).each(function(name){
5862                         var original = this[name];
5863                         if (original) this[name] = original.bind(this);
5864                 }, this);
5865                 return initialize.apply(this, arguments);
5866         };
5867 };
5868
5869
5870 // Begin: Source/Class/Class.Occlude.js
5871 /*
5872 ---
5873
5874 script: Class.Occlude.js
5875
5876 name: Class.Occlude
5877
5878 description: Prevents a class from being applied to a DOM element twice.
5879
5880 license: MIT-style license.
5881
5882 authors:
5883   - Aaron Newton
5884
5885 requires:
5886   - Core/Class
5887   - Core/Element
5888   - /MooTools.More
5889
5890 provides: [Class.Occlude]
5891
5892 ...
5893 */
5894
5895 Class.Occlude = new Class({
5896
5897         occlude: function(property, element){
5898                 element = document.id(element || this.element);
5899                 var instance = element.retrieve(property || this.property);
5900                 if (instance && !this.occluded)
5901                         return (this.occluded = instance);
5902
5903                 this.occluded = false;
5904                 element.store(property || this.property, this);
5905                 return this.occluded;
5906         }
5907
5908 });
5909
5910
5911 // Begin: Source/Element/Element.Dimensions.js
5912 /*
5913 ---
5914
5915 name: Element.Dimensions
5916
5917 description: Contains methods to work with size, scroll, or positioning of Elements and the window object.
5918
5919 license: MIT-style license.
5920
5921 credits:
5922   - Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html).
5923   - Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html).
5924
5925 requires: [Element, Element.Style]
5926
5927 provides: [Element.Dimensions]
5928
5929 ...
5930 */
5931
5932 (function(){
5933
5934 var element = document.createElement('div'),
5935         child = document.createElement('div');
5936 element.style.height = '0';
5937 element.appendChild(child);
5938 var brokenOffsetParent = (child.offsetParent === element);
5939 element = child = null;
5940
5941 var isOffset = function(el){
5942         return styleString(el, 'position') != 'static' || isBody(el);
5943 };
5944
5945 var isOffsetStatic = function(el){
5946         return isOffset(el) || (/^(?:table|td|th)$/i).test(el.tagName);
5947 };
5948
5949 Element.implement({
5950
5951         scrollTo: function(x, y){
5952                 if (isBody(this)){
5953                         this.getWindow().scrollTo(x, y);
5954                 } else {
5955                         this.scrollLeft = x;
5956                         this.scrollTop = y;
5957                 }
5958                 return this;
5959         },
5960
5961         getSize: function(){
5962                 if (isBody(this)) return this.getWindow().getSize();
5963                 return {x: this.offsetWidth, y: this.offsetHeight};
5964         },
5965
5966         getScrollSize: function(){
5967                 if (isBody(this)) return this.getWindow().getScrollSize();
5968                 return {x: this.scrollWidth, y: this.scrollHeight};
5969         },
5970
5971         getScroll: function(){
5972                 if (isBody(this)) return this.getWindow().getScroll();
5973                 return {x: this.scrollLeft, y: this.scrollTop};
5974         },
5975
5976         getScrolls: function(){
5977                 var element = this.parentNode, position = {x: 0, y: 0};
5978                 while (element && !isBody(element)){
5979                         position.x += element.scrollLeft;
5980                         position.y += element.scrollTop;
5981                         element = element.parentNode;
5982                 }
5983                 return position;
5984         },
5985
5986         getOffsetParent: brokenOffsetParent ? function(){
5987                 var element = this;
5988                 if (isBody(element) || styleString(element, 'position') == 'fixed') return null;
5989
5990                 var isOffsetCheck = (styleString(element, 'position') == 'static') ? isOffsetStatic : isOffset;
5991                 while ((element = element.parentNode)){
5992                         if (isOffsetCheck(element)) return element;
5993                 }
5994                 return null;
5995         } : function(){
5996                 var element = this;
5997                 if (isBody(element) || styleString(element, 'position') == 'fixed') return null;
5998
5999                 try {
6000                         return element.offsetParent;
6001                 } catch(e) {}
6002                 return null;
6003         },
6004
6005         getOffsets: function(){
6006                 if (this.getBoundingClientRect && !Browser.Platform.ios){
6007                         var bound = this.getBoundingClientRect(),
6008                                 html = document.id(this.getDocument().documentElement),
6009                                 htmlScroll = html.getScroll(),
6010                                 elemScrolls = this.getScrolls(),
6011                                 isFixed = (styleString(this, 'position') == 'fixed');
6012
6013                         return {
6014                                 x: bound.left.toInt() + elemScrolls.x + ((isFixed) ? 0 : htmlScroll.x) - html.clientLeft,
6015                                 y: bound.top.toInt()  + elemScrolls.y + ((isFixed) ? 0 : htmlScroll.y) - html.clientTop
6016                         };
6017                 }
6018
6019                 var element = this, position = {x: 0, y: 0};
6020                 if (isBody(this)) return position;
6021
6022                 while (element && !isBody(element)){
6023                         position.x += element.offsetLeft;
6024                         position.y += element.offsetTop;
6025
6026                         if (Browser.firefox){
6027                                 if (!borderBox(element)){
6028                                         position.x += leftBorder(element);
6029                                         position.y += topBorder(element);
6030                                 }
6031                                 var parent = element.parentNode;
6032                                 if (parent && styleString(parent, 'overflow') != 'visible'){
6033                                         position.x += leftBorder(parent);
6034                                         position.y += topBorder(parent);
6035                                 }
6036                         } else if (element != this && Browser.safari){
6037                                 position.x += leftBorder(element);
6038                                 position.y += topBorder(element);
6039                         }
6040
6041                         element = element.offsetParent;
6042                 }
6043                 if (Browser.firefox && !borderBox(this)){
6044                         position.x -= leftBorder(this);
6045                         position.y -= topBorder(this);
6046                 }
6047                 return position;
6048         },
6049
6050         getPosition: function(relative){
6051                 var offset = this.getOffsets(),
6052                         scroll = this.getScrolls();
6053                 var position = {
6054                         x: offset.x - scroll.x,
6055                         y: offset.y - scroll.y
6056                 };
6057
6058                 if (relative && (relative = document.id(relative))){
6059                         var relativePosition = relative.getPosition();
6060                         return {x: position.x - relativePosition.x - leftBorder(relative), y: position.y - relativePosition.y - topBorder(relative)};
6061                 }
6062                 return position;
6063         },
6064
6065         getCoordinates: function(element){
6066                 if (isBody(this)) return this.getWindow().getCoordinates();
6067                 var position = this.getPosition(element),
6068                         size = this.getSize();
6069                 var obj = {
6070                         left: position.x,
6071                         top: position.y,
6072                         width: size.x,
6073                         height: size.y
6074                 };
6075                 obj.right = obj.left + obj.width;
6076                 obj.bottom = obj.top + obj.height;
6077                 return obj;
6078         },
6079
6080         computePosition: function(obj){
6081                 return {
6082                         left: obj.x - styleNumber(this, 'margin-left'),
6083                         top: obj.y - styleNumber(this, 'margin-top')
6084                 };
6085         },
6086
6087         setPosition: function(obj){
6088                 return this.setStyles(this.computePosition(obj));
6089         }
6090
6091 });
6092
6093
6094 [Document, Window].invoke('implement', {
6095
6096         getSize: function(){
6097                 var doc = getCompatElement(this);
6098                 return {x: doc.clientWidth, y: doc.clientHeight};
6099         },
6100
6101         getScroll: function(){
6102                 var win = this.getWindow(), doc = getCompatElement(this);
6103                 return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop};
6104         },
6105
6106         getScrollSize: function(){
6107                 var doc = getCompatElement(this),
6108                         min = this.getSize(),
6109                         body = this.getDocument().body;
6110
6111                 return {x: Math.max(doc.scrollWidth, body.scrollWidth, min.x), y: Math.max(doc.scrollHeight, body.scrollHeight, min.y)};
6112         },
6113
6114         getPosition: function(){
6115                 return {x: 0, y: 0};
6116         },
6117
6118         getCoordinates: function(){
6119                 var size = this.getSize();
6120                 return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x};
6121         }
6122
6123 });
6124
6125 // private methods
6126
6127 var styleString = Element.getComputedStyle;
6128
6129 function styleNumber(element, style){
6130         return styleString(element, style).toInt() || 0;
6131 }
6132
6133 function borderBox(element){
6134         return styleString(element, '-moz-box-sizing') == 'border-box';
6135 }
6136
6137 function topBorder(element){
6138         return styleNumber(element, 'border-top-width');
6139 }
6140
6141 function leftBorder(element){
6142         return styleNumber(element, 'border-left-width');
6143 }
6144
6145 function isBody(element){
6146         return (/^(?:body|html)$/i).test(element.tagName);
6147 }
6148
6149 function getCompatElement(element){
6150         var doc = element.getDocument();
6151         return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
6152 }
6153
6154 })();
6155
6156 //aliases
6157 Element.alias({position: 'setPosition'}); //compatability
6158
6159 [Window, Document, Element].invoke('implement', {
6160
6161         getHeight: function(){
6162                 return this.getSize().y;
6163         },
6164
6165         getWidth: function(){
6166                 return this.getSize().x;
6167         },
6168
6169         getScrollTop: function(){
6170                 return this.getScroll().y;
6171         },
6172
6173         getScrollLeft: function(){
6174                 return this.getScroll().x;
6175         },
6176
6177         getScrollHeight: function(){
6178                 return this.getScrollSize().y;
6179         },
6180
6181         getScrollWidth: function(){
6182                 return this.getScrollSize().x;
6183         },
6184
6185         getTop: function(){
6186                 return this.getPosition().y;
6187         },
6188
6189         getLeft: function(){
6190                 return this.getPosition().x;
6191         }
6192
6193 });
6194
6195
6196 // Begin: Source/Element/Element.Measure.js
6197 /*
6198 ---
6199
6200 script: Element.Measure.js
6201
6202 name: Element.Measure
6203
6204 description: Extends the Element native object to include methods useful in measuring dimensions.
6205
6206 credits: "Element.measure / .expose methods by Daniel Steigerwald License: MIT-style license. Copyright: Copyright (c) 2008 Daniel Steigerwald, daniel.steigerwald.cz"
6207
6208 license: MIT-style license
6209
6210 authors:
6211   - Aaron Newton
6212
6213 requires:
6214   - Core/Element.Style
6215   - Core/Element.Dimensions
6216   - /MooTools.More
6217
6218 provides: [Element.Measure]
6219
6220 ...
6221 */
6222
6223 (function(){
6224
6225 var getStylesList = function(styles, planes){
6226         var list = [];
6227         Object.each(planes, function(directions){
6228                 Object.each(directions, function(edge){
6229                         styles.each(function(style){
6230                                 list.push(style + '-' + edge + (style == 'border' ? '-width' : ''));
6231                         });
6232                 });
6233         });
6234         return list;
6235 };
6236
6237 var calculateEdgeSize = function(edge, styles){
6238         var total = 0;
6239         Object.each(styles, function(value, style){
6240                 if (style.test(edge)) total = total + value.toInt();
6241         });
6242         return total;
6243 };
6244
6245 var isVisible = function(el){
6246         return !!(!el || el.offsetHeight || el.offsetWidth);
6247 };
6248
6249
6250 Element.implement({
6251
6252         measure: function(fn){
6253                 if (isVisible(this)) return fn.call(this);
6254                 var parent = this.getParent(),
6255                         toMeasure = [];
6256                 while (!isVisible(parent) && parent != document.body){
6257                         toMeasure.push(parent.expose());
6258                         parent = parent.getParent();
6259                 }
6260                 var restore = this.expose(),
6261                         result = fn.call(this);
6262                 restore();
6263                 toMeasure.each(function(restore){
6264                         restore();
6265                 });
6266                 return result;
6267         },
6268
6269         expose: function(){
6270                 if (this.getStyle('display') != 'none') return function(){};
6271                 var before = this.style.cssText;
6272                 this.setStyles({
6273                         display: 'block',
6274                         position: 'absolute',
6275                         visibility: 'hidden'
6276                 });
6277                 return function(){
6278                         this.style.cssText = before;
6279                 }.bind(this);
6280         },
6281
6282         getDimensions: function(options){
6283                 options = Object.merge({computeSize: false}, options);
6284                 var dim = {x: 0, y: 0};
6285
6286                 var getSize = function(el, options){
6287                         return (options.computeSize) ? el.getComputedSize(options) : el.getSize();
6288                 };
6289
6290                 var parent = this.getParent('body');
6291
6292                 if (parent && this.getStyle('display') == 'none'){
6293                         dim = this.measure(function(){
6294                                 return getSize(this, options);
6295                         });
6296                 } else if (parent){
6297                         try { //safari sometimes crashes here, so catch it
6298                                 dim = getSize(this, options);
6299                         }catch(e){}
6300                 }
6301
6302                 return Object.append(dim, (dim.x || dim.x === 0) ? {
6303                                 width: dim.x,
6304                                 height: dim.y
6305                         } : {
6306                                 x: dim.width,
6307                                 y: dim.height
6308                         }
6309                 );
6310         },
6311
6312         getComputedSize: function(options){
6313                 //<1.2compat>
6314                 //legacy support for my stupid spelling error
6315                 if (options && options.plains) options.planes = options.plains;
6316                 //</1.2compat>
6317
6318                 options = Object.merge({
6319                         styles: ['padding','border'],
6320                         planes: {
6321                                 height: ['top','bottom'],
6322                                 width: ['left','right']
6323                         },
6324                         mode: 'both'
6325                 }, options);
6326
6327                 var styles = {},
6328                         size = {width: 0, height: 0},
6329                         dimensions;
6330
6331                 if (options.mode == 'vertical'){
6332                         delete size.width;
6333                         delete options.planes.width;
6334                 } else if (options.mode == 'horizontal'){
6335                         delete size.height;
6336                         delete options.planes.height;
6337                 }
6338
6339                 getStylesList(options.styles, options.planes).each(function(style){
6340                         styles[style] = this.getStyle(style).toInt();
6341                 }, this);
6342
6343                 Object.each(options.planes, function(edges, plane){
6344
6345                         var capitalized = plane.capitalize(),
6346                                 style = this.getStyle(plane);
6347
6348                         if (style == 'auto' && !dimensions) dimensions = this.getDimensions();
6349
6350                         style = styles[plane] = (style == 'auto') ? dimensions[plane] : style.toInt();
6351                         size['total' + capitalized] = style;
6352
6353                         edges.each(function(edge){
6354                                 var edgesize = calculateEdgeSize(edge, styles);
6355                                 size['computed' + edge.capitalize()] = edgesize;
6356                                 size['total' + capitalized] += edgesize;
6357                         });
6358
6359                 }, this);
6360
6361                 return Object.append(size, styles);
6362         }
6363
6364 });
6365
6366 })();
6367
6368
6369 // Begin: Source/Element/Element.Position.js
6370 /*
6371 ---
6372
6373 script: Element.Position.js
6374
6375 name: Element.Position
6376
6377 description: Extends the Element native object to include methods useful positioning elements relative to others.
6378
6379 license: MIT-style license
6380
6381 authors:
6382   - Aaron Newton
6383   - Jacob Thornton
6384
6385 requires:
6386   - Core/Options
6387   - Core/Element.Dimensions
6388   - Element.Measure
6389
6390 provides: [Element.Position]
6391
6392 ...
6393 */
6394
6395 (function(original){
6396
6397 var local = Element.Position = {
6398
6399         options: {/*
6400                 edge: false,
6401                 returnPos: false,
6402                 minimum: {x: 0, y: 0},
6403                 maximum: {x: 0, y: 0},
6404                 relFixedPosition: false,
6405                 ignoreMargins: false,
6406                 ignoreScroll: false,
6407                 allowNegative: false,*/
6408                 relativeTo: document.body,
6409                 position: {
6410                         x: 'center', //left, center, right
6411                         y: 'center' //top, center, bottom
6412                 },
6413                 offset: {x: 0, y: 0}
6414         },
6415
6416         getOptions: function(element, options){
6417                 options = Object.merge({}, local.options, options);
6418                 local.setPositionOption(options);
6419                 local.setEdgeOption(options);
6420                 local.setOffsetOption(element, options);
6421                 local.setDimensionsOption(element, options);
6422                 return options;
6423         },
6424
6425         setPositionOption: function(options){
6426                 options.position = local.getCoordinateFromValue(options.position);
6427         },
6428
6429         setEdgeOption: function(options){
6430                 var edgeOption = local.getCoordinateFromValue(options.edge);
6431                 options.edge = edgeOption ? edgeOption :
6432                         (options.position.x == 'center' && options.position.y == 'center') ? {x: 'center', y: 'center'} :
6433                         {x: 'left', y: 'top'};
6434         },
6435
6436         setOffsetOption: function(element, options){
6437                 var parentOffset = {x: 0, y: 0},
6438                         offsetParent = element.measure(function(){
6439                                 return document.id(this.getOffsetParent());
6440                         }),
6441                         parentScroll = offsetParent.getScroll();
6442
6443                 if (!offsetParent || offsetParent == element.getDocument().body) return;
6444                 parentOffset = offsetParent.measure(function(){
6445                         var position = this.getPosition();
6446                         if (this.getStyle('position') == 'fixed'){
6447                                 var scroll = window.getScroll();
6448                                 position.x += scroll.x;
6449                                 position.y += scroll.y;
6450                         }
6451                         return position;
6452                 });
6453
6454                 options.offset = {
6455                         parentPositioned: offsetParent != document.id(options.relativeTo),
6456                         x: options.offset.x - parentOffset.x + parentScroll.x,
6457                         y: options.offset.y - parentOffset.y + parentScroll.y
6458                 };
6459         },
6460
6461         setDimensionsOption: function(element, options){
6462                 options.dimensions = element.getDimensions({
6463                         computeSize: true,
6464                         styles: ['padding', 'border', 'margin']
6465                 });
6466         },
6467
6468         getPosition: function(element, options){
6469                 var position = {};
6470                 options = local.getOptions(element, options);
6471                 var relativeTo = document.id(options.relativeTo) || document.body;
6472
6473                 local.setPositionCoordinates(options, position, relativeTo);
6474                 if (options.edge) local.toEdge(position, options);
6475
6476                 var offset = options.offset;
6477                 position.left = ((position.x >= 0 || offset.parentPositioned || options.allowNegative) ? position.x : 0).toInt();
6478                 position.top = ((position.y >= 0 || offset.parentPositioned || options.allowNegative) ? position.y : 0).toInt();
6479
6480                 local.toMinMax(position, options);
6481
6482                 if (options.relFixedPosition || relativeTo.getStyle('position') == 'fixed') local.toRelFixedPosition(relativeTo, position);
6483                 if (options.ignoreScroll) local.toIgnoreScroll(relativeTo, position);
6484                 if (options.ignoreMargins) local.toIgnoreMargins(position, options);
6485
6486                 position.left = Math.ceil(position.left);
6487                 position.top = Math.ceil(position.top);
6488                 delete position.x;
6489                 delete position.y;
6490
6491                 return position;
6492         },
6493
6494         setPositionCoordinates: function(options, position, relativeTo){
6495                 var offsetY = options.offset.y,
6496                         offsetX = options.offset.x,
6497                         calc = (relativeTo == document.body) ? window.getScroll() : relativeTo.getPosition(),
6498                         top = calc.y,
6499                         left = calc.x,
6500                         winSize = window.getSize();
6501
6502                 switch(options.position.x){
6503                         case 'left': position.x = left + offsetX; break;
6504                         case 'right': position.x = left + offsetX + relativeTo.offsetWidth; break;
6505                         default: position.x = left + ((relativeTo == document.body ? winSize.x : relativeTo.offsetWidth) / 2) + offsetX; break;
6506                 }
6507
6508                 switch(options.position.y){
6509                         case 'top': position.y = top + offsetY; break;
6510                         case 'bottom': position.y = top + offsetY + relativeTo.offsetHeight; break;
6511                         default: position.y = top + ((relativeTo == document.body ? winSize.y : relativeTo.offsetHeight) / 2) + offsetY; break;
6512                 }
6513         },
6514
6515         toMinMax: function(position, options){
6516                 var xy = {left: 'x', top: 'y'}, value;
6517                 ['minimum', 'maximum'].each(function(minmax){
6518                         ['left', 'top'].each(function(lr){
6519                                 value = options[minmax] ? options[minmax][xy[lr]] : null;
6520                                 if (value != null && ((minmax == 'minimum') ? position[lr] < value : position[lr] > value)) position[lr] = value;
6521                         });
6522                 });
6523         },
6524
6525         toRelFixedPosition: function(relativeTo, position){
6526                 var winScroll = window.getScroll();
6527                 position.top += winScroll.y;
6528                 position.left += winScroll.x;
6529         },
6530
6531         toIgnoreScroll: function(relativeTo, position){
6532                 var relScroll = relativeTo.getScroll();
6533                 position.top -= relScroll.y;
6534                 position.left -= relScroll.x;
6535         },
6536
6537         toIgnoreMargins: function(position, options){
6538                 position.left += options.edge.x == 'right'
6539                         ? options.dimensions['margin-right']
6540                         : (options.edge.x != 'center'
6541                                 ? -options.dimensions['margin-left']
6542                                 : -options.dimensions['margin-left'] + ((options.dimensions['margin-right'] + options.dimensions['margin-left']) / 2));
6543
6544                 position.top += options.edge.y == 'bottom'
6545                         ? options.dimensions['margin-bottom']
6546                         : (options.edge.y != 'center'
6547                                 ? -options.dimensions['margin-top']
6548                                 : -options.dimensions['margin-top'] + ((options.dimensions['margin-bottom'] + options.dimensions['margin-top']) / 2));
6549         },
6550
6551         toEdge: function(position, options){
6552                 var edgeOffset = {},
6553                         dimensions = options.dimensions,
6554                         edge = options.edge;
6555
6556                 switch(edge.x){
6557                         case 'left': edgeOffset.x = 0; break;
6558                         case 'right': edgeOffset.x = -dimensions.x - dimensions.computedRight - dimensions.computedLeft; break;
6559                         // center
6560                         default: edgeOffset.x = -(Math.round(dimensions.totalWidth / 2)); break;
6561                 }
6562
6563                 switch(edge.y){
6564                         case 'top': edgeOffset.y = 0; break;
6565                         case 'bottom': edgeOffset.y = -dimensions.y - dimensions.computedTop - dimensions.computedBottom; break;
6566                         // center
6567                         default: edgeOffset.y = -(Math.round(dimensions.totalHeight / 2)); break;
6568                 }
6569
6570                 position.x += edgeOffset.x;
6571                 position.y += edgeOffset.y;
6572         },
6573
6574         getCoordinateFromValue: function(option){
6575                 if (typeOf(option) != 'string') return option;
6576                 option = option.toLowerCase();
6577
6578                 return {
6579                         x: option.test('left') ? 'left'
6580                                 : (option.test('right') ? 'right' : 'center'),
6581                         y: option.test(/upper|top/) ? 'top'
6582                                 : (option.test('bottom') ? 'bottom' : 'center')
6583                 };
6584         }
6585
6586 };
6587
6588 Element.implement({
6589
6590         position: function(options){
6591                 if (options && (options.x != null || options.y != null)){
6592                         return (original ? original.apply(this, arguments) : this);
6593                 }
6594                 var position = this.setStyle('position', 'absolute').calculatePosition(options);
6595                 return (options && options.returnPos) ? position : this.setStyles(position);
6596         },
6597
6598         calculatePosition: function(options){
6599                 return local.getPosition(this, options);
6600         }
6601
6602 });
6603
6604 })(Element.prototype.position);
6605
6606
6607 // Begin: Source/Element/Element.Shortcuts.js
6608 /*
6609 ---
6610
6611 script: Element.Shortcuts.js
6612
6613 name: Element.Shortcuts
6614
6615 description: Extends the Element native object to include some shortcut methods.
6616
6617 license: MIT-style license
6618
6619 authors:
6620   - Aaron Newton
6621
6622 requires:
6623   - Core/Element.Style
6624   - /MooTools.More
6625
6626 provides: [Element.Shortcuts]
6627
6628 ...
6629 */
6630
6631 Element.implement({
6632
6633         isDisplayed: function(){
6634                 return this.getStyle('display') != 'none';
6635         },
6636
6637         isVisible: function(){
6638                 var w = this.offsetWidth,
6639                         h = this.offsetHeight;
6640                 return (w == 0 && h == 0) ? false : (w > 0 && h > 0) ? true : this.style.display != 'none';
6641         },
6642
6643         toggle: function(){
6644                 return this[this.isDisplayed() ? 'hide' : 'show']();
6645         },
6646
6647         hide: function(){
6648                 var d;
6649                 try {
6650                         //IE fails here if the element is not in the dom
6651                         d = this.getStyle('display');
6652                 } catch(e){}
6653                 if (d == 'none') return this;
6654                 return this.store('element:_originalDisplay', d || '').setStyle('display', 'none');
6655         },
6656
6657         show: function(display){
6658                 if (!display && this.isDisplayed()) return this;
6659                 display = display || this.retrieve('element:_originalDisplay') || 'block';
6660                 return this.setStyle('display', (display == 'none') ? 'block' : display);
6661         },
6662
6663         swapClass: function(remove, add){
6664                 return this.removeClass(remove).addClass(add);
6665         }
6666
6667 });
6668
6669 Document.implement({
6670
6671         clearSelection: function(){
6672                 if (window.getSelection){
6673                         var selection = window.getSelection();
6674                         if (selection && selection.removeAllRanges) selection.removeAllRanges();
6675                 } else if (document.selection && document.selection.empty){
6676                         try {
6677                                 //IE fails here if selected element is not in dom
6678                                 document.selection.empty();
6679                         } catch(e){}
6680                 }
6681         }
6682
6683 });
6684
6685
6686 // Begin: Source/Forms/OverText.js
6687 /*
6688 ---
6689
6690 script: OverText.js
6691
6692 name: OverText
6693
6694 description: Shows text over an input that disappears when the user clicks into it. The text remains hidden if the user adds a value.
6695
6696 license: MIT-style license
6697
6698 authors:
6699   - Aaron Newton
6700
6701 requires:
6702   - Core/Options
6703   - Core/Events
6704   - Core/Element.Event
6705   - Class.Binds
6706   - Class.Occlude
6707   - Element.Position
6708   - Element.Shortcuts
6709
6710 provides: [OverText]
6711
6712 ...
6713 */
6714
6715 var OverText = new Class({
6716
6717         Implements: [Options, Events, Class.Occlude],
6718
6719         Binds: ['reposition', 'assert', 'focus', 'hide'],
6720
6721         options: {/*
6722                 textOverride: null,
6723                 onFocus: function(){},
6724                 onTextHide: function(textEl, inputEl){},
6725                 onTextShow: function(textEl, inputEl){}, */
6726                 element: 'label',
6727                 labelClass: 'overTxtLabel',
6728                 positionOptions: {
6729                         position: 'upperLeft',
6730                         edge: 'upperLeft',
6731                         offset: {
6732                                 x: 4,
6733                                 y: 2
6734                         }
6735                 },
6736                 poll: false,
6737                 pollInterval: 250,
6738                 wrap: false
6739         },
6740
6741         property: 'OverText',
6742
6743         initialize: function(element, options){
6744                 element = this.element = document.id(element);
6745
6746                 if (this.occlude()) return this.occluded;
6747                 this.setOptions(options);
6748
6749                 this.attach(element);
6750                 OverText.instances.push(this);
6751
6752                 if (this.options.poll) this.poll();
6753         },
6754
6755         toElement: function(){
6756                 return this.element;
6757         },
6758
6759         attach: function(){
6760                 var element = this.element,
6761                         options = this.options,
6762                         value = options.textOverride || element.get('alt') || element.get('title');
6763
6764                 if (!value) return this;
6765
6766                 var text = this.text = new Element(options.element, {
6767                         'class': options.labelClass,
6768                         styles: {
6769                                 lineHeight: 'normal',
6770                                 position: 'absolute',
6771                                 cursor: 'text'
6772                         },
6773                         html: value,
6774                         events: {
6775                                 click: this.hide.pass(options.element == 'label', this)
6776                         }
6777                 }).inject(element, 'after');
6778
6779                 if (options.element == 'label'){
6780                         if (!element.get('id')) element.set('id', 'input_' + String.uniqueID());
6781                         text.set('for', element.get('id'));
6782                 }
6783
6784                 if (options.wrap){
6785                         this.textHolder = new Element('div.overTxtWrapper', {
6786                                 styles: {
6787                                         lineHeight: 'normal',
6788                                         position: 'relative'
6789                                 }
6790                         }).grab(text).inject(element, 'before');
6791                 }
6792
6793                 return this.enable();
6794         },
6795
6796         destroy: function(){
6797                 this.element.eliminate(this.property); // Class.Occlude storage
6798                 this.disable();
6799                 if (this.text) this.text.destroy();
6800                 if (this.textHolder) this.textHolder.destroy();
6801                 return this;
6802         },
6803
6804         disable: function(){
6805                 this.element.removeEvents({
6806                         focus: this.focus,
6807                         blur: this.assert,
6808                         change: this.assert
6809                 });
6810                 window.removeEvent('resize', this.reposition);
6811                 this.hide(true, true);
6812                 return this;
6813         },
6814
6815         enable: function(){
6816                 this.element.addEvents({
6817                         focus: this.focus,
6818                         blur: this.assert,
6819                         change: this.assert
6820                 });
6821                 window.addEvent('resize', this.reposition);
6822                 this.reposition();
6823                 return this;
6824         },
6825
6826         wrap: function(){
6827                 if (this.options.element == 'label'){
6828                         if (!this.element.get('id')) this.element.set('id', 'input_' + String.uniqueID());
6829                         this.text.set('for', this.element.get('id'));
6830                 }
6831         },
6832
6833         startPolling: function(){
6834                 this.pollingPaused = false;
6835                 return this.poll();
6836         },
6837
6838         poll: function(stop){
6839                 //start immediately
6840                 //pause on focus
6841                 //resumeon blur
6842                 if (this.poller && !stop) return this;
6843                 if (stop){
6844                         clearInterval(this.poller);
6845                 } else {
6846                         this.poller = (function(){
6847                                 if (!this.pollingPaused) this.assert(true);
6848                         }).periodical(this.options.pollInterval, this);
6849                 }
6850
6851                 return this;
6852         },
6853
6854         stopPolling: function(){
6855                 this.pollingPaused = true;
6856                 return this.poll(true);
6857         },
6858
6859         focus: function(){
6860                 if (this.text && (!this.text.isDisplayed() || this.element.get('disabled'))) return this;
6861                 return this.hide();
6862         },
6863
6864         hide: function(suppressFocus, force){
6865                 if (this.text && (this.text.isDisplayed() && (!this.element.get('disabled') || force))){
6866                         this.text.hide();
6867                         this.fireEvent('textHide', [this.text, this.element]);
6868                         this.pollingPaused = true;
6869                         if (!suppressFocus){
6870                                 try {
6871                                         this.element.fireEvent('focus');
6872                                         this.element.focus();
6873                                 } catch(e){} //IE barfs if you call focus on hidden elements
6874                         }
6875                 }
6876                 return this;
6877         },
6878
6879         show: function(){
6880                 if (document.id(this.text) && !this.text.isDisplayed()){
6881                         this.text.show();
6882                         this.reposition();
6883                         this.fireEvent('textShow', [this.text, this.element]);
6884                         this.pollingPaused = false;
6885                 }
6886                 return this;
6887         },
6888
6889         test: function(){
6890                 return !this.element.get('value');
6891         },
6892
6893         assert: function(suppressFocus){
6894                 return this[this.test() ? 'show' : 'hide'](suppressFocus);
6895         },
6896
6897         reposition: function(){
6898                 this.assert(true);
6899                 if (!this.element.isVisible()) return this.stopPolling().hide();
6900                 if (this.text && this.test()){
6901                         this.text.position(Object.merge(this.options.positionOptions, {
6902                                 relativeTo: this.element
6903                         }));
6904                 }
6905                 return this;
6906         }
6907
6908 });
6909
6910 OverText.instances = [];
6911
6912 Object.append(OverText, {
6913
6914         each: function(fn){
6915                 return OverText.instances.each(function(ot, i){
6916                         if (ot.element && ot.text) fn.call(OverText, ot, i);
6917                 });
6918         },
6919
6920         update: function(){
6921
6922                 return OverText.each(function(ot){
6923                         return ot.reposition();
6924                 });
6925
6926         },
6927
6928         hideAll: function(){
6929
6930                 return OverText.each(function(ot){
6931                         return ot.hide(true, true);
6932                 });
6933
6934         },
6935
6936         showAll: function(){
6937                 return OverText.each(function(ot){
6938                         return ot.show();
6939                 });
6940         }
6941
6942 });
6943
6944
6945
6946 // Begin: Source/Utilities/IframeShim.js
6947 /*
6948 ---
6949
6950 script: IframeShim.js
6951
6952 name: IframeShim
6953
6954 description: Defines IframeShim, a class for obscuring select lists and flash objects in IE.
6955
6956 license: MIT-style license
6957
6958 authors:
6959   - Aaron Newton
6960
6961 requires:
6962   - Core/Element.Event
6963   - Core/Element.Style
6964   - Core/Options
6965   - Core/Events
6966   - /Element.Position
6967   - /Class.Occlude
6968
6969 provides: [IframeShim]
6970
6971 ...
6972 */
6973
6974 var IframeShim = new Class({
6975
6976         Implements: [Options, Events, Class.Occlude],
6977
6978         options: {
6979                 className: 'iframeShim',
6980                 src: 'javascript:false;document.write("");',
6981                 display: false,
6982                 zIndex: null,
6983                 margin: 0,
6984                 offset: {x: 0, y: 0},
6985                 browsers: (Browser.ie6 || (Browser.firefox && Browser.version < 3 && Browser.Platform.mac))
6986         },
6987
6988         property: 'IframeShim',
6989
6990         initialize: function(element, options){
6991                 this.element = document.id(element);
6992                 if (this.occlude()) return this.occluded;
6993                 this.setOptions(options);
6994                 this.makeShim();
6995                 return this;
6996         },
6997
6998         makeShim: function(){
6999                 if (this.options.browsers){
7000                         var zIndex = this.element.getStyle('zIndex').toInt();
7001
7002                         if (!zIndex){
7003                                 zIndex = 1;
7004                                 var pos = this.element.getStyle('position');
7005                                 if (pos == 'static' || !pos) this.element.setStyle('position', 'relative');
7006                                 this.element.setStyle('zIndex', zIndex);
7007                         }
7008                         zIndex = ((this.options.zIndex != null || this.options.zIndex === 0) && zIndex > this.options.zIndex) ? this.options.zIndex : zIndex - 1;
7009                         if (zIndex < 0) zIndex = 1;
7010                         this.shim = new Element('iframe', {
7011                                 src: this.options.src,
7012                                 scrolling: 'no',
7013                                 frameborder: 0,
7014                                 styles: {
7015                                         zIndex: zIndex,
7016                                         position: 'absolute',
7017                                         border: 'none',
7018                                         filter: 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)'
7019                                 },
7020                                 'class': this.options.className
7021                         }).store('IframeShim', this);
7022                         var inject = (function(){
7023                                 this.shim.inject(this.element, 'after');
7024                                 this[this.options.display ? 'show' : 'hide']();
7025                                 this.fireEvent('inject');
7026                         }).bind(this);
7027                         if (!IframeShim.ready) window.addEvent('load', inject);
7028                         else inject();
7029                 } else {
7030                         this.position = this.hide = this.show = this.dispose = Function.from(this);
7031                 }
7032         },
7033
7034         position: function(){
7035                 if (!IframeShim.ready || !this.shim) return this;
7036                 var size = this.element.measure(function(){
7037                         return this.getSize();
7038                 });
7039                 if (this.options.margin != undefined){
7040                         size.x = size.x - (this.options.margin * 2);
7041                         size.y = size.y - (this.options.margin * 2);
7042                         this.options.offset.x += this.options.margin;
7043                         this.options.offset.y += this.options.margin;
7044                 }
7045                 this.shim.set({width: size.x, height: size.y}).position({
7046                         relativeTo: this.element,
7047                         offset: this.options.offset
7048                 });
7049                 return this;
7050         },
7051
7052         hide: function(){
7053                 if (this.shim) this.shim.setStyle('display', 'none');
7054                 return this;
7055         },
7056
7057         show: function(){
7058                 if (this.shim) this.shim.setStyle('display', 'block');
7059                 return this.position();
7060         },
7061
7062         dispose: function(){
7063                 if (this.shim) this.shim.dispose();
7064                 return this;
7065         },
7066
7067         destroy: function(){
7068                 if (this.shim) this.shim.destroy();
7069                 return this;
7070         }
7071
7072 });
7073
7074 window.addEvent('load', function(){
7075         IframeShim.ready = true;
7076 });
7077
7078
7079 // Begin: Source/Interface/Mask.js
7080 /*
7081 ---
7082
7083 script: Mask.js
7084
7085 name: Mask
7086
7087 description: Creates a mask element to cover another.
7088
7089 license: MIT-style license
7090
7091 authors:
7092   - Aaron Newton
7093
7094 requires:
7095   - Core/Options
7096   - Core/Events
7097   - Core/Element.Event
7098   - /Class.Binds
7099   - /Element.Position
7100   - /IframeShim
7101
7102 provides: [Mask]
7103
7104 ...
7105 */
7106
7107 var Mask = new Class({
7108
7109         Implements: [Options, Events],
7110
7111         Binds: ['position'],
7112
7113         options: {/*
7114                 onShow: function(){},
7115                 onHide: function(){},
7116                 onDestroy: function(){},
7117                 onClick: function(event){},
7118                 inject: {
7119                         where: 'after',
7120                         target: null,
7121                 },
7122                 hideOnClick: false,
7123                 id: null,
7124                 destroyOnHide: false,*/
7125                 style: {},
7126                 'class': 'mask',
7127                 maskMargins: false,
7128                 useIframeShim: true,
7129                 iframeShimOptions: {}
7130         },
7131
7132         initialize: function(target, options){
7133                 this.target = document.id(target) || document.id(document.body);
7134                 this.target.store('mask', this);
7135                 this.setOptions(options);
7136                 this.render();
7137                 this.inject();
7138         },
7139
7140         render: function(){
7141                 this.element = new Element('div', {
7142                         'class': this.options['class'],
7143                         id: this.options.id || 'mask-' + String.uniqueID(),
7144                         styles: Object.merge({}, this.options.style, {
7145                                 display: 'none'
7146                         }),
7147                         events: {
7148                                 click: function(event){
7149                                         this.fireEvent('click', event);
7150                                         if (this.options.hideOnClick) this.hide();
7151                                 }.bind(this)
7152                         }
7153                 });
7154
7155                 this.hidden = true;
7156         },
7157
7158         toElement: function(){
7159                 return this.element;
7160         },
7161
7162         inject: function(target, where){
7163                 where = where || (this.options.inject ? this.options.inject.where : '') || this.target == document.body ? 'inside' : 'after';
7164                 target = target || (this.options.inject && this.options.inject.target) || this.target;
7165
7166                 this.element.inject(target, where);
7167
7168                 if (this.options.useIframeShim){
7169                         this.shim = new IframeShim(this.element, this.options.iframeShimOptions);
7170
7171                         this.addEvents({
7172                                 show: this.shim.show.bind(this.shim),
7173                                 hide: this.shim.hide.bind(this.shim),
7174                                 destroy: this.shim.destroy.bind(this.shim)
7175                         });
7176                 }
7177         },
7178
7179         position: function(){
7180                 this.resize(this.options.width, this.options.height);
7181
7182                 this.element.position({
7183                         relativeTo: this.target,
7184                         position: 'topLeft',
7185                         ignoreMargins: !this.options.maskMargins,
7186                         ignoreScroll: this.target == document.body
7187                 });
7188
7189                 return this;
7190         },
7191
7192         resize: function(x, y){
7193                 var opt = {
7194                         styles: ['padding', 'border']
7195                 };
7196                 if (this.options.maskMargins) opt.styles.push('margin');
7197
7198                 var dim = this.target.getComputedSize(opt);
7199                 if (this.target == document.body){
7200                         this.element.setStyles({width: 0, height: 0});
7201                         var win = window.getScrollSize();
7202                         if (dim.totalHeight < win.y) dim.totalHeight = win.y;
7203                         if (dim.totalWidth < win.x) dim.totalWidth = win.x;
7204                 }
7205                 this.element.setStyles({
7206                         width: Array.pick([x, dim.totalWidth, dim.x]),
7207                         height: Array.pick([y, dim.totalHeight, dim.y])
7208                 });
7209
7210                 return this;
7211         },
7212
7213         show: function(){
7214                 if (!this.hidden) return this;
7215
7216                 window.addEvent('resize', this.position);
7217                 this.position();
7218                 this.showMask.apply(this, arguments);
7219
7220                 return this;
7221         },
7222
7223         showMask: function(){
7224                 this.element.setStyle('display', 'block');
7225                 this.hidden = false;
7226                 this.fireEvent('show');
7227         },
7228
7229         hide: function(){
7230                 if (this.hidden) return this;
7231
7232                 window.removeEvent('resize', this.position);
7233                 this.hideMask.apply(this, arguments);
7234                 if (this.options.destroyOnHide) return this.destroy();
7235
7236                 return this;
7237         },
7238
7239         hideMask: function(){
7240                 this.element.setStyle('display', 'none');
7241                 this.hidden = true;
7242                 this.fireEvent('hide');
7243         },
7244
7245         toggle: function(){
7246                 this[this.hidden ? 'show' : 'hide']();
7247         },
7248
7249         destroy: function(){
7250                 this.hide();
7251                 this.element.destroy();
7252                 this.fireEvent('destroy');
7253                 this.target.eliminate('mask');
7254         }
7255
7256 });
7257
7258 Element.Properties.mask = {
7259
7260         set: function(options){
7261                 var mask = this.retrieve('mask');
7262                 if (mask) mask.destroy();
7263                 return this.eliminate('mask').store('mask:options', options);
7264         },
7265
7266         get: function(){
7267                 var mask = this.retrieve('mask');
7268                 if (!mask){
7269                         mask = new Mask(this, this.retrieve('mask:options'));
7270                         this.store('mask', mask);
7271                 }
7272                 return mask;
7273         }
7274
7275 };
7276
7277 Element.implement({
7278
7279         mask: function(options){
7280                 if (options) this.set('mask', options);
7281                 this.get('mask').show();
7282                 return this;
7283         },
7284
7285         unmask: function(){
7286                 this.get('mask').hide();
7287                 return this;
7288         }
7289
7290 });
7291
7292
7293 // Begin: Source/Utilities/DOMReady.js
7294 /*
7295 ---
7296
7297 name: DOMReady
7298
7299 description: Contains the custom event domready.
7300
7301 license: MIT-style license.
7302
7303 requires: [Browser, Element, Element.Event]
7304
7305 provides: [DOMReady, DomReady]
7306
7307 ...
7308 */
7309
7310 (function(window, document){
7311
7312 var ready,
7313         loaded,
7314         checks = [],
7315         shouldPoll,
7316         timer,
7317         testElement = document.createElement('div');
7318
7319 var domready = function(){
7320         clearTimeout(timer);
7321         if (ready) return;
7322         Browser.loaded = ready = true;
7323         document.removeListener('DOMContentLoaded', domready).removeListener('readystatechange', check);
7324
7325         document.fireEvent('domready');
7326         window.fireEvent('domready');
7327 };
7328
7329 var check = function(){
7330         for (var i = checks.length; i--;) if (checks[i]()){
7331                 domready();
7332                 return true;
7333         }
7334         return false;
7335 };
7336
7337 var poll = function(){
7338         clearTimeout(timer);
7339         if (!check()) timer = setTimeout(poll, 10);
7340 };
7341
7342 document.addListener('DOMContentLoaded', domready);
7343
7344 /*<ltIE8>*/
7345 // doScroll technique by Diego Perini http://javascript.nwbox.com/IEContentLoaded/
7346 // testElement.doScroll() throws when the DOM is not ready, only in the top window
7347 var doScrollWorks = function(){
7348         try {
7349                 testElement.doScroll();
7350                 return true;
7351         } catch (e){}
7352         return false;
7353 };
7354 // If doScroll works already, it can't be used to determine domready
7355 //   e.g. in an iframe
7356 if (testElement.doScroll && !doScrollWorks()){
7357         checks.push(doScrollWorks);
7358         shouldPoll = true;
7359 }
7360 /*</ltIE8>*/
7361
7362 if (document.readyState) checks.push(function(){
7363         var state = document.readyState;
7364         return (state == 'loaded' || state == 'complete');
7365 });
7366
7367 if ('onreadystatechange' in document) document.addListener('readystatechange', check);
7368 else shouldPoll = true;
7369
7370 if (shouldPoll) poll();
7371
7372 Element.Events.domready = {
7373         onAdd: function(fn){
7374                 if (ready) fn.call(this);
7375         }
7376 };
7377
7378 // Make sure that domready fires before load
7379 Element.Events.load = {
7380         base: 'load',
7381         onAdd: function(fn){
7382                 if (loaded && this == window) fn.call(this);
7383         },
7384         condition: function(){
7385                 if (this == window){
7386                         domready();
7387                         delete Element.Events.load;
7388                 }
7389                 return true;
7390         }
7391 };
7392
7393 // This is based on the custom load event
7394 window.addEvent('load', function(){
7395         loaded = true;
7396 });
7397
7398 })(window, document);
7399
7400
7401 // Begin: Source/Element/Element.Pin.js
7402 /*
7403 ---
7404
7405 script: Element.Pin.js
7406
7407 name: Element.Pin
7408
7409 description: Extends the Element native object to include the pin method useful for fixed positioning for elements.
7410
7411 license: MIT-style license
7412
7413 authors:
7414   - Aaron Newton
7415
7416 requires:
7417   - Core/Element.Event
7418   - Core/Element.Dimensions
7419   - Core/Element.Style
7420   - /MooTools.More
7421
7422 provides: [Element.Pin]
7423
7424 ...
7425 */
7426
7427 (function(){
7428         var supportsPositionFixed = false,
7429                 supportTested = false;
7430
7431         var testPositionFixed = function(){
7432                 var test = new Element('div').setStyles({
7433                         position: 'fixed',
7434                         top: 0,
7435                         right: 0
7436                 }).inject(document.body);
7437                 supportsPositionFixed = (test.offsetTop === 0);
7438                 test.dispose();
7439                 supportTested = true;
7440         };
7441
7442         Element.implement({
7443
7444                 pin: function(enable, forceScroll){
7445                         if (!supportTested) testPositionFixed();
7446                         if (this.getStyle('display') == 'none') return this;
7447
7448                         var pinnedPosition,
7449                                 scroll = window.getScroll(),
7450                                 parent,
7451                                 scrollFixer;
7452
7453                         if (enable !== false){
7454                                 pinnedPosition = this.getPosition(supportsPositionFixed ? document.body : this.getOffsetParent());
7455                                 if (!this.retrieve('pin:_pinned')){
7456                                         var currentPosition = {
7457                                                 top: pinnedPosition.y - scroll.y,
7458                                                 left: pinnedPosition.x - scroll.x
7459                                         };
7460
7461                                         if (supportsPositionFixed && !forceScroll){
7462                                                 this.setStyle('position', 'fixed').setStyles(currentPosition);
7463                                         } else {
7464
7465                                                 parent = this.getOffsetParent();
7466                                                 var position = this.getPosition(parent),
7467                                                         styles = this.getStyles('left', 'top');
7468
7469                                                 if (parent && styles.left == 'auto' || styles.top == 'auto') this.setPosition(position);
7470                                                 if (this.getStyle('position') == 'static') this.setStyle('position', 'absolute');
7471
7472                                                 position = {
7473                                                         x: styles.left.toInt() - scroll.x,
7474                                                         y: styles.top.toInt() - scroll.y
7475                                                 };
7476
7477                                                 scrollFixer = function(){
7478                                                         if (!this.retrieve('pin:_pinned')) return;
7479                                                         var scroll = window.getScroll();
7480                                                         this.setStyles({
7481                                                                 left: position.x + scroll.x,
7482                                                                 top: position.y + scroll.y
7483                                                         });
7484                                                 }.bind(this);
7485
7486                                                 this.store('pin:_scrollFixer', scrollFixer);
7487                                                 window.addEvent('scroll', scrollFixer);
7488                                         }
7489                                         this.store('pin:_pinned', true);
7490                                 }
7491
7492                         } else {
7493                                 if (!this.retrieve('pin:_pinned')) return this;
7494
7495                                 parent = this.getParent();
7496                                 var offsetParent = (parent.getComputedStyle('position') != 'static' ? parent : parent.getOffsetParent());
7497
7498                                 pinnedPosition = this.getPosition(offsetParent);
7499
7500                                 this.store('pin:_pinned', false);
7501                                 scrollFixer = this.retrieve('pin:_scrollFixer');
7502                                 if (!scrollFixer){
7503                                         this.setStyles({
7504                                                 position: 'absolute',
7505                                                 top: pinnedPosition.y + scroll.y,
7506                                                 left: pinnedPosition.x + scroll.x
7507                                         });
7508                                 } else {
7509                                         this.store('pin:_scrollFixer', null);
7510                                         window.removeEvent('scroll', scrollFixer);
7511                                 }
7512                                 this.removeClass('isPinned');
7513                         }
7514                         return this;
7515                 },
7516
7517                 unpin: function(){
7518                         return this.pin(false);
7519                 },
7520
7521                 togglePin: function(){
7522                         return this.pin(!this.retrieve('pin:_pinned'));
7523                 }
7524
7525         });
7526
7527 //<1.2compat>
7528 Element.alias('togglepin', 'togglePin');
7529 //</1.2compat>
7530
7531 })();
7532
7533
7534 // Begin: Source/Types/Object.Extras.js
7535 /*
7536 ---
7537
7538 script: Object.Extras.js
7539
7540 name: Object.Extras
7541
7542 description: Extra Object generics, like getFromPath which allows a path notation to child elements.
7543
7544 license: MIT-style license
7545
7546 authors:
7547   - Aaron Newton
7548
7549 requires:
7550   - Core/Object
7551   - /MooTools.More
7552
7553 provides: [Object.Extras]
7554
7555 ...
7556 */
7557
7558 (function(){
7559
7560 var defined = function(value){
7561         return value != null;
7562 };
7563
7564 var hasOwnProperty = Object.prototype.hasOwnProperty;
7565
7566 Object.extend({
7567
7568         getFromPath: function(source, parts){
7569                 if (typeof parts == 'string') parts = parts.split('.');
7570                 for (var i = 0, l = parts.length; i < l; i++){
7571                         if (hasOwnProperty.call(source, parts[i])) source = source[parts[i]];
7572                         else return null;
7573                 }
7574                 return source;
7575         },
7576
7577         cleanValues: function(object, method){
7578                 method = method || defined;
7579                 for (var key in object) if (!method(object[key])){
7580                         delete object[key];
7581                 }
7582                 return object;
7583         },
7584
7585         erase: function(object, key){
7586                 if (hasOwnProperty.call(object, key)) delete object[key];
7587                 return object;
7588         },
7589
7590         run: function(object){
7591                 var args = Array.slice(arguments, 1);
7592                 for (var key in object) if (object[key].apply){
7593                         object[key].apply(object, args);
7594                 }
7595                 return object;
7596         }
7597
7598 });
7599
7600 })();
7601
7602
7603 // Begin: Source/Core/Clientcide.js
7604 /*
7605 ---
7606
7607 name: Clientcide
7608
7609 description: The Clientcide namespace.
7610
7611 license: MIT-style license.
7612
7613 provides: Clientcide
7614
7615 ...
7616 */
7617 var Clientcide = {
7618         version: '3.0.10',
7619         assetLocation: "http://github.com/anutron/clientcide/raw/master/Assets",
7620         setAssetLocation: function(baseHref) {
7621                 Clientcide.assetLocation = baseHref;
7622                 if (Clientcide.preloaded) Clientcide.preLoadCss();
7623         },
7624         preLoadCss: function(){
7625                 if (window.StickyWin && StickyWin.ui) StickyWin.ui();
7626                 if (window.StickyWin && StickyWin.pointy) StickyWin.pointy();
7627                 Clientcide.preloaded = true;
7628                 return true;
7629         },
7630         preloaded: false
7631 };
7632 (function(){
7633         if (!window.addEvent) return;
7634         var preload = function(){
7635                 if (window.dbug) dbug.log('preloading clientcide css');
7636                 if (!Clientcide.preloaded) Clientcide.preLoadCss();
7637         };
7638         window.addEvent('domready', preload);
7639         window.addEvent('load', preload);
7640 })();
7641 setCNETAssetBaseHref = Clientcide.setAssetLocation;
7642
7643
7644 // Begin: Source/Core/dbug.js
7645 /*
7646 ---
7647
7648 name: dbug
7649
7650 description: A wrapper for Firebug console.* statements.
7651
7652 license: MIT-style license.
7653
7654 authors:
7655 - Aaron Newton
7656
7657 provides: dbug
7658
7659 ...
7660 */
7661 var dbug = {
7662         logged: [],
7663         timers: {},
7664         firebug: false,
7665         enabled: false,
7666         log: function() {
7667                 dbug.logged.push(arguments);
7668         },
7669         nolog: function(msg) {
7670                 dbug.logged.push(arguments);
7671         },
7672         time: function(name){
7673                 dbug.timers[name] = new Date().getTime();
7674         },
7675         timeEnd: function(name){
7676                 if (dbug.timers[name]) {
7677                         var end = new Date().getTime() - dbug.timers[name];
7678                         dbug.timers[name] = false;
7679                         dbug.log('%s: %s', name, end);
7680                 } else dbug.log('no such timer: %s', name);
7681         },
7682         enable: function(silent) {
7683                 var con = window.firebug ? firebug.d.console.cmd : window.console;
7684
7685                 if((!!window.console && !!window.console.warn) || window.firebug) {
7686                         try {
7687                                 dbug.enabled = true;
7688                                 dbug.log = function(){
7689                                                 try {
7690                                                         (con.debug || con.log).apply(con, arguments);
7691                                                 } catch(e) {
7692                                                         console.log(Array.slice(arguments));
7693                                                 }
7694                                 };
7695                                 dbug.time = function(){
7696                                         con.time.apply(con, arguments);
7697                                 };
7698                                 dbug.timeEnd = function(){
7699                                         con.timeEnd.apply(con, arguments);
7700                                 };
7701                                 if(!silent) dbug.log('enabling dbug');
7702                                 for(var i=0;i<dbug.logged.length;i++){ dbug.log.apply(con, dbug.logged[i]); }
7703                                 dbug.logged=[];
7704                         } catch(e) {
7705                                 dbug.enable.delay(400);
7706                         }
7707                 }
7708         },
7709         disable: function(){
7710                 if(dbug.firebug) dbug.enabled = false;
7711                 dbug.log = dbug.nolog;
7712                 dbug.time = function(){};
7713                 dbug.timeEnd = function(){};
7714         },
7715         cookie: function(set){
7716                 var value = document.cookie.match('(?:^|;)\\s*jsdebug=([^;]*)');
7717                 var debugCookie = value ? unescape(value[1]) : false;
7718                 if((set == null && debugCookie != 'true') || (set != null && set)) {
7719                         dbug.enable();
7720                         dbug.log('setting debugging cookie');
7721                         var date = new Date();
7722                         date.setTime(date.getTime()+(24*60*60*1000));
7723                         document.cookie = 'jsdebug=true;expires='+date.toGMTString()+';path=/;';
7724                 } else dbug.disableCookie();
7725         },
7726         disableCookie: function(){
7727                 dbug.log('disabling debugging cookie');
7728                 document.cookie = 'jsdebug=false;path=/;';
7729         },
7730         conditional: function(fn, fnIfError) {
7731                 if (dbug.enabled) {
7732                         return fn();
7733                 } else {
7734                         try {
7735                                 return fn();
7736                         } catch(e) {
7737                                 if (fnIfError) fnIfError(e);
7738                         }
7739                 }
7740         }
7741 };
7742
7743 (function(){
7744         var fb = !!window.console || !!window.firebug;
7745         var con = window.firebug ? window.firebug.d.console.cmd : window.console;
7746         var debugMethods = ['debug','info','warn','error','assert','dir','dirxml'];
7747         var otherMethods = ['trace','group','groupEnd','profile','profileEnd','count'];
7748         function set(methodList, defaultFunction) {
7749
7750                 var getLogger = function(method) {
7751                         return function(){
7752                                 con[method].apply(con, arguments);
7753                         };
7754                 };
7755
7756                 for(var i = 0; i < methodList.length; i++){
7757                         var method = methodList[i];
7758                         if (fb && con[method]) {
7759                                 dbug[method] = getLogger(method);
7760                         } else {
7761                                 dbug[method] = defaultFunction;
7762                         }
7763                 }
7764         };
7765         set(debugMethods, dbug.log);
7766         set(otherMethods, function(){});
7767 })();
7768 if ((!!window.console && !!window.console.warn) || window.firebug){
7769         dbug.firebug = true;
7770         var value = document.cookie.match('(?:^|;)\\s*jsdebug=([^;]*)');
7771         var debugCookie = value ? unescape(value[1]) : false;
7772         if(window.location.href.indexOf("jsdebug=true")>0 || debugCookie=='true') dbug.enable();
7773         if(debugCookie=='true')dbug.log('debugging cookie enabled');
7774         if(window.location.href.indexOf("jsdebugCookie=true")>0){
7775                 dbug.cookie();
7776                 if(!dbug.enabled)dbug.enable();
7777         }
7778         if(window.location.href.indexOf("jsdebugCookie=false")>0)dbug.disableCookie();
7779 }
7780
7781
7782 // Begin: Source/UI/StyleWriter.js
7783 /*
7784 ---
7785 name: StyleWriter
7786
7787 description: Provides a simple method for injecting a css style element into the DOM if it's not already present.
7788
7789 license: MIT-Style License
7790
7791 requires: [Core/Class, Core/DomReady, Core/Element, dbug]
7792
7793 provides: StyleWriter
7794
7795 ...
7796 */
7797
7798 var StyleWriter = new Class({
7799         createStyle: function(css, id) {
7800                 window.addEvent('domready', function(){
7801                         try {
7802                                 if (document.id(id) && id) return;
7803                                 var style = new Element('style', {id: id||''}).inject($$('head')[0]);
7804                                 if (Browser.ie) style.styleSheet.cssText = css;
7805                                 else style.set('text', css);
7806                         }catch(e){dbug.log('error: %s',e);}
7807                 }.bind(this));
7808         }
7809 });
7810
7811 // Begin: Source/UI/StickyWin.js
7812 /*
7813 ---
7814
7815 name: StickyWin
7816
7817 description: Creates a div within the page with the specified contents at the location relative to the element you specify; basically an in-page popup maker.
7818
7819 license: MIT-Style License
7820
7821 requires: [
7822   Core/DomReady,
7823   Core/Slick.Finder,
7824   More/Element.Position,
7825   More/Class.Binds,
7826   More/Element.Shortcuts,
7827   More/Element.Pin,
7828   More/IframeShim,
7829   More/Object.Extras,
7830   Clientcide,
7831   StyleWriter
7832 ]
7833
7834 provides: [StickyWin, StickyWin.Stacker]
7835 ...
7836 */
7837
7838
7839 var StickyWin = new Class({
7840         Binds: ['destroy', 'hide', 'togglepin', 'esc'],
7841         Implements: [Options, Events, StyleWriter],
7842         options: {
7843 //              onDisplay: function(){},
7844 //              onClose: function(){},
7845 //              onDestroy: function(){},
7846                 closeClassName: 'closeSticky',
7847                 pinClassName: 'pinSticky',
7848                 content: '',
7849                 zIndex: 10000,
7850                 className: '',
7851 //              id: ... set above in initialize function
7852 /*      these are the defaults for Element.position anyway
7853                 ************************************************
7854                 edge: false, //see Element.position
7855                 position: 'center', //center, corner == upperLeft, upperRight, bottomLeft, bottomRight
7856                 offset: {x:0,y:0},
7857                 relativeTo: document.body, */
7858                 width: false,
7859                 height: false,
7860                 timeout: -1,
7861                 allowMultipleByClass: true,
7862                 allowMultiple: true,
7863                 showNow: true,
7864                 useIframeShim: true,
7865                 iframeShimSelector: '',
7866                 destroyOnClose: false,
7867                 closeOnClickOut: false,
7868                 closeOnEsc: false,
7869                 getWindowManager: function(){ return StickyWin.WM; }
7870         },
7871
7872         css: '.SWclearfix:after {content: "."; display: block; height: 0; clear: both; visibility: hidden;}'+
7873                  '.SWclearfix {display: inline-table;} * html .SWclearfix {height: 1%;} .SWclearfix {display: block;}',
7874
7875         initialize: function(options){
7876                 this.options.inject = this.options.inject || {
7877                         target: document.body,
7878                         where: 'bottom'
7879                 };
7880                 this.setOptions(options);
7881                 this.windowManager = this.options.getWindowManager();
7882                 this.id = this.options.id || 'StickyWin_'+new Date().getTime();
7883                 this.makeWindow();
7884                 if (this.windowManager) this.windowManager.add(this);
7885
7886                 if (this.options.content) this.setContent(this.options.content);
7887                 if (this.options.timeout > 0) {
7888                         this.addEvent('onDisplay', function(){
7889                                 this.hide.delay(this.options.timeout, this);
7890                         }.bind(this));
7891                 }
7892                 //add css for clearfix
7893                 this.createStyle(this.css, 'StickyWinClearFix');
7894                 if (this.options.closeOnClickOut || this.options.closeOnEsc) this.attach();
7895                 if (this.options.destroyOnClose) this.addEvent('close', this.destroy);
7896                 if (this.options.showNow) this.show();
7897         },
7898         toElement: function(){
7899                 return this.element;
7900         },
7901         attach: function(dettach){
7902                 var method = dettach ? 'removeEvents' : 'addEvents';
7903                 var events = {};
7904                 if (this.options.closeOnClickOut) events.click = this.esc;
7905                 if (this.options.closeOnEsc) events.keyup = this.esc;
7906                 document[method](events);
7907         },
7908         esc: function(e) {
7909                 if (e.key == "esc") this.hide();
7910                 if (e.type == "click" && this.element != e.target && !this.element.contains(e.target)) this.hide();
7911         },
7912         makeWindow: function(){
7913                 this.destroyOthers();
7914                 if (!document.id(this.id)) {
7915                         this.win = new Element('div', {
7916                                 id: this.id
7917                         }).addClass(this.options.className).addClass('StickyWinInstance').addClass('SWclearfix').setStyles({
7918                                 display: 'none',
7919                                 position: 'absolute',
7920                                 zIndex: this.options.zIndex
7921                         }).inject(this.options.inject.target, this.options.inject.where).store('StickyWin', this);
7922                 } else this.win = document.id(this.id);
7923                 this.element = this.win;
7924                 if (this.options.width && typeOf(this.options.width.toInt())=="number") this.win.setStyle('width', this.options.width.toInt());
7925                 if (this.options.height && typeOf(this.options.height.toInt())=="number") this.win.setStyle('height', this.options.height.toInt());
7926                 return this;
7927         },
7928         show: function(suppressEvent){
7929                 this.showWin();
7930                 if (!suppressEvent) this.fireEvent('display');
7931                 if (this.options.useIframeShim) this.showIframeShim();
7932                 this.visible = true;
7933                 return this;
7934         },
7935         showWin: function(){
7936                 if (this.windowManager) this.windowManager.focus(this);
7937                 if (!this.positioned) this.position();
7938                 this.win.show();
7939         },
7940         hide: function(suppressEvent){
7941                 if (typeOf(suppressEvent) == "event" || !suppressEvent) this.fireEvent('close');
7942                 this.hideWin();
7943                 if (this.options.useIframeShim) this.hideIframeShim();
7944                 this.visible = false;
7945                 return this;
7946         },
7947         hideWin: function(){
7948                 this.win.setStyle('display','none');
7949         },
7950         destroyOthers: function() {
7951                 if (!this.options.allowMultipleByClass || !this.options.allowMultiple) {
7952                         $$('div.StickyWinInstance').each(function(sw) {
7953                                 if (!this.options.allowMultiple || (!this.options.allowMultipleByClass && sw.hasClass(this.options.className)))
7954                                         sw.retrieve('StickyWin').destroy();
7955                         }, this);
7956                 }
7957         },
7958         setContent: function(html) {
7959                 if (this.win.getChildren().length>0) this.win.empty();
7960                 if (typeOf(html) == "string") this.win.set('html', html);
7961                 else if (document.id(html)) this.win.adopt(html);
7962                 this.win.getElements('.'+this.options.closeClassName).each(function(el){
7963                         el.addEvent('click', this.hide);
7964                 }, this);
7965                 this.win.getElements('.'+this.options.pinClassName).each(function(el){
7966                         el.addEvent('click', this.togglepin);
7967                 }, this);
7968                 return this;
7969         },
7970         position: function(options){
7971                 this.positioned = true;
7972                 this.setOptions(options);
7973                 this.win.position(
7974                         Object.cleanValues({
7975                                 allowNegative: [this.options.allowNegative, this.options.relativeTo != document.body].pick(),
7976                                 relativeTo: this.options.relativeTo,
7977                                 position: this.options.position,
7978                                 offset: this.options.offset,
7979                                 edge: this.options.edge
7980                         })
7981                 );
7982                 if (this.shim) this.shim.position();
7983                 return this;
7984         },
7985         pin: function(pin) {
7986                 if (!this.win.pin) {
7987                         dbug.log('you must include element.pin.js!');
7988                         return this;
7989                 }
7990                 this.pinned = pin != null && pin;
7991                 this.win.pin(pin);
7992                 return this;
7993         },
7994         unpin: function(){
7995                 return this.pin(false);
7996         },
7997         togglepin: function(){
7998                 return this.pin(!this.pinned);
7999         },
8000         makeIframeShim: function(){
8001                 if (!this.shim){
8002                         var el = (this.options.iframeShimSelector)?this.win.getElement(this.options.iframeShimSelector):this.win;
8003                         this.shim = new IframeShim(el, {
8004                                 display: false,
8005                                 name: 'StickyWinShim'
8006                         });
8007                 }
8008         },
8009         showIframeShim: function(){
8010                 if (this.options.useIframeShim) {
8011                         this.makeIframeShim();
8012                         this.shim.show();
8013                 }
8014         },
8015         hideIframeShim: function(){
8016                 if (this.shim) this.shim.hide();
8017         },
8018         destroy: function(){
8019                 this.destroyed = true;
8020                 this.attach(true);
8021                 if (this.windowManager) this.windowManager.remove(this);
8022                 if (this.win) this.win.destroy();
8023                 if (this.options.useIframeShim && this.shim) this.shim.destroy();
8024                 if (document.id('modalOverlay')) document.id('modalOverlay').destroy();
8025                 this.fireEvent('destroy');
8026         }
8027 });
8028
8029 StickyWin.Stacker = new Class({
8030         Implements: [Options, Events],
8031         Binds: ['click'],
8032         instances: [],
8033         options: {
8034                 zIndexBase: 9000
8035         },
8036         initialize: function(options) {
8037                 this.setOptions(options);
8038         },
8039         add: function(sw) {
8040                 this.instances.include(sw);
8041                 $(sw).addEvent('mousedown', this.click);
8042         },
8043         click: function(e) {
8044                 this.instances.each(function(sw){
8045                         var el = $(sw);
8046                         if (el == e.target || el.contains($(e.target))) this.focus(sw);
8047                 }, this);
8048         },
8049         focus: function(instance){
8050                 if (this.focused == instance) return;
8051                 this.focused = instance;
8052                 if (instance) this.instances.erase(instance).push(instance);
8053                 this.instances.each(function(current, i){
8054                         $(current).setStyle('z-index', this.options.zIndexBase + i);
8055                 }, this);
8056                 this.focused = instance;
8057         },
8058         remove: function(sw) {
8059                 this.instances.erase(sw);
8060                 $(sw).removeEvent('click', this.click);
8061         }
8062 });
8063 StickyWin.WM = new StickyWin.Stacker();
8064
8065 // Begin: Source/UI/StickyWin.Modal.js
8066 /*
8067 ---
8068
8069 name: StickyWin.Modal
8070
8071 description: This script extends StickyWin and StickyWin.Fx classes to add Mask functionality.
8072
8073 license: MIT-Style License
8074
8075 requires: [More/Mask, StickyWin]
8076
8077 provides: StickyWin.Modal
8078 ...
8079 */
8080 StickyWin.Modal = new Class({
8081
8082         Extends: StickyWin,
8083
8084         options: {
8085                 modalize: true,
8086                 maskOptions: {
8087                         style: {
8088                                 'background-color':'#333',
8089                                 opacity:0.8
8090                         }
8091                 },
8092                 hideOnClick: true,
8093                 getWindowManager: function(){ return StickyWin.ModalWM; }
8094         },
8095
8096         initialize: function(options) {
8097                 this.options.maskTarget = this.options.maskTarget || document.body;
8098                 this.setOptions(options);
8099                 this.mask = new Mask(this.options.maskTarget, this.options.maskOptions).addEvent('click', function() {
8100                         if (this.options.hideOnClick) this.hide();
8101                 }.bind(this));
8102                 this.parent(options);
8103         },
8104
8105         show: function(showModal){
8106                 if ([showModal, this.options.modalize].pick()) this.mask.show();
8107                 this.parent();
8108         },
8109
8110         hide: function(hideModal){
8111                 if ([hideModal, true].pick()) this.mask.hide();
8112                 this.parent();
8113         },
8114
8115         destroy: function(){
8116                 this.mask.destroy();
8117                 this.parent.apply(this, arguments);
8118         }
8119
8120 });
8121
8122 StickyWin.ModalWM = new StickyWin.Stacker({
8123         zIndexBase: 11000
8124 });
8125 if (StickyWin.Fx) StickyWin.Fx.Modal = StickyWin.Modal;
8126
8127 // Begin: Source/Types/String.Extras.js
8128 /*
8129 ---
8130
8131 script: String.Extras.js
8132
8133 name: String.Extras
8134
8135 description: Extends the String native object to include methods useful in managing various kinds of strings (query strings, urls, html, etc).
8136
8137 license: MIT-style license
8138
8139 authors:
8140   - Aaron Newton
8141   - Guillermo Rauch
8142   - Christopher Pitt
8143
8144 requires:
8145   - Core/String
8146   - Core/Array
8147   - MooTools.More
8148
8149 provides: [String.Extras]
8150
8151 ...
8152 */
8153
8154 (function(){
8155
8156 var special = {
8157         'a': /[àáâãäåăą]/g,
8158         'A': /[ÀÁÂÃÄÅĂĄ]/g,
8159         'c': /[ćčç]/g,
8160         'C': /[ĆČÇ]/g,
8161         'd': /[ďđ]/g,
8162         'D': /[ĎÐ]/g,
8163         'e': /[èéêëěę]/g,
8164         'E': /[ÈÉÊËĚĘ]/g,
8165         'g': /[ğ]/g,
8166         'G': /[Ğ]/g,
8167         'i': /[ìíîï]/g,
8168         'I': /[ÌÍÎÏ]/g,
8169         'l': /[ĺľł]/g,
8170         'L': /[ĹĽŁ]/g,
8171         'n': /[ñňń]/g,
8172         'N': /[ÑŇŃ]/g,
8173         'o': /[òóôõöøő]/g,
8174         'O': /[ÒÓÔÕÖØ]/g,
8175         'r': /[řŕ]/g,
8176         'R': /[ŘŔ]/g,
8177         's': /[ššş]/g,
8178         'S': /[ŠŞŚ]/g,
8179         't': /[ťţ]/g,
8180         'T': /[ŤŢ]/g,
8181         'ue': /[ü]/g,
8182         'UE': /[Ü]/g,
8183         'u': /[ùúûůµ]/g,
8184         'U': /[ÙÚÛŮ]/g,
8185         'y': /[ÿý]/g,
8186         'Y': /[ŸÝ]/g,
8187         'z': /[žźż]/g,
8188         'Z': /[ŽŹŻ]/g,
8189         'th': /[þ]/g,
8190         'TH': /[Þ]/g,
8191         'dh': /[ð]/g,
8192         'DH': /[Ð]/g,
8193         'ss': /[ß]/g,
8194         'oe': /[œ]/g,
8195         'OE': /[Œ]/g,
8196         'ae': /[æ]/g,
8197         'AE': /[Æ]/g
8198 },
8199
8200 tidy = {
8201         ' ': /[\xa0\u2002\u2003\u2009]/g,
8202         '*': /[\xb7]/g,
8203         '\'': /[\u2018\u2019]/g,
8204         '"': /[\u201c\u201d]/g,
8205         '...': /[\u2026]/g,
8206         '-': /[\u2013]/g,
8207 //      '--': /[\u2014]/g,
8208         '&raquo;': /[\uFFFD]/g
8209 },
8210
8211 conversions = {
8212         ms: 1,
8213         s: 1000,
8214         m: 6e4,
8215         h: 36e5
8216 },
8217
8218 findUnits = /(\d*.?\d+)([msh]+)/;
8219
8220 var walk = function(string, replacements){
8221         var result = string, key;
8222         for (key in replacements) result = result.replace(replacements[key], key);
8223         return result;
8224 };
8225
8226 var getRegexForTag = function(tag, contents){
8227         tag = tag || '';
8228         var regstr = contents ? "<" + tag + "(?!\\w)[^>]*>([\\s\\S]*?)<\/" + tag + "(?!\\w)>" : "<\/?" + tag + "([^>]+)?>",
8229                 reg = new RegExp(regstr, "gi");
8230         return reg;
8231 };
8232
8233 String.implement({
8234
8235         standardize: function(){
8236                 return walk(this, special);
8237         },
8238
8239         repeat: function(times){
8240                 return new Array(times + 1).join(this);
8241         },
8242
8243         pad: function(length, str, direction){
8244                 if (this.length >= length) return this;
8245
8246                 var pad = (str == null ? ' ' : '' + str)
8247                         .repeat(length - this.length)
8248                         .substr(0, length - this.length);
8249
8250                 if (!direction || direction == 'right') return this + pad;
8251                 if (direction == 'left') return pad + this;
8252
8253                 return pad.substr(0, (pad.length / 2).floor()) + this + pad.substr(0, (pad.length / 2).ceil());
8254         },
8255
8256         getTags: function(tag, contents){
8257                 return this.match(getRegexForTag(tag, contents)) || [];
8258         },
8259
8260         stripTags: function(tag, contents){
8261                 return this.replace(getRegexForTag(tag, contents), '');
8262         },
8263
8264         tidy: function(){
8265                 return walk(this, tidy);
8266         },
8267
8268         truncate: function(max, trail, atChar){
8269                 var string = this;
8270                 if (trail == null && arguments.length == 1) trail = '…';
8271                 if (string.length > max){
8272                         string = string.substring(0, max);
8273                         if (atChar){
8274                                 var index = string.lastIndexOf(atChar);
8275                                 if (index != -1) string = string.substr(0, index);
8276                         }
8277                         if (trail) string += trail;
8278                 }
8279                 return string;
8280         },
8281
8282         ms: function(){
8283           // "Borrowed" from https://gist.github.com/1503944
8284                 var units = findUnits.exec(this);
8285                 if (units == null) return Number(this);
8286                 return Number(units[1]) * conversions[units[2]];
8287         }
8288
8289 });
8290
8291 })();
8292
8293
8294 // Begin: Source/UI/StickyWin.UI.js
8295  /*
8296 ---
8297 name: StickyWin.UI
8298
8299 description: Creates an html holder for in-page popups using a default style.
8300
8301 license: MIT-Style License
8302
8303 requires: [Core/Element.Style, More/String.Extras, StyleWriter, StickyWin]
8304
8305 provides: StickyWin.UI
8306 ...
8307 */
8308 StickyWin.UI = new Class({
8309         Implements: [Options, StyleWriter],
8310         options: {
8311                 width: 300,
8312                 css: "div.DefaultStickyWin {font-family:verdana; font-size:11px; line-height: 13px;position: relative;}"+
8313                         "div.DefaultStickyWin div.top{-moz-user-select: none;-khtml-user-select: none;}"+
8314                         "div.DefaultStickyWin div.top_ul{background:url({%baseHref%}full.png) top left no-repeat; height:30px; width:15px; float:left}"+
8315                         "div.DefaultStickyWin div.top_ur{position:relative; left:0px !important; left:-4px; background:url({%baseHref%}full.png) top right !important; height:30px; margin:0px 0px 0px 15px !important; margin-right:-4px; padding:0px}"+
8316                         "div.DefaultStickyWin h1.caption{clear: none !important; margin:0px !important; overflow: hidden; padding:0 !important; font-weight:bold; color:#555; font-size:14px !important; position:relative; top:8px !important; left:5px !important; float: left; height: 22px !important;}"+
8317                         "div.DefaultStickyWin div.middle, div.DefaultStickyWin div.closeBody {background:url({%baseHref%}body.png) top left repeat-y; margin:0px 20px 0px 0px !important;       margin-bottom: -3px; position: relative;        top: 0px !important; top: -3px;}"+
8318                         "div.DefaultStickyWin div.body{background:url({%baseHref%}body.png) top right repeat-y; padding:8px 23px 8px 0px !important; margin-left:5px !important; position:relative; right:-20px !important; z-index: 1;}"+
8319                         "div.DefaultStickyWin div.bottom{clear:both;}"+
8320                         "div.DefaultStickyWin div.bottom_ll{background:url({%baseHref%}full.png) bottom left no-repeat; width:15px; height:15px; float:left}"+
8321                         "div.DefaultStickyWin div.bottom_lr{background:url({%baseHref%}full.png) bottom right; position:relative; left:0px !important; left:-4px; margin:0px 0px 0px 15px !important; margin-right:-4px; height:15px}"+
8322                         "div.DefaultStickyWin div.closeButtons{text-align: center; background:url({%baseHref%}body.png) top right repeat-y; padding: 4px 30px 8px 0px; margin-left:5px; position:relative; right:-20px}"+
8323                         "div.DefaultStickyWin a.button:hover{background:url({%baseHref%}big_button_over.gif) repeat-x}"+
8324                         "div.DefaultStickyWin a.button {background:url({%baseHref%}big_button.gif) repeat-x; margin: 2px 8px 2px 8px; padding: 2px 12px; cursor:pointer; border: 1px solid #999 !important; text-decoration:none; color: #000 !important;}"+
8325                         "div.DefaultStickyWin div.closeButton{width:13px; height:13px; background:url({%baseHref%}closebtn.gif) no-repeat; position: absolute; right: 0px; margin:10px 15px 0px 0px !important; cursor:pointer;top:0px}"+
8326                         "div.DefaultStickyWin div.dragHandle {  width: 11px;    height: 25px;   position: relative;     top: 5px;       left: -3px;     cursor: move;   background: url({%baseHref%}drag_corner.gif); float: left;}",
8327                 cornerHandle: false,
8328                 cssClass: '',
8329                 buttons: [],
8330                 cssId: 'defaultStickyWinStyle',
8331                 cssClassName: 'DefaultStickyWin',
8332                 closeButton: true
8333 /*      These options are deprecated:
8334                 closeTxt: false,
8335                 onClose: function(){},
8336                 confirmTxt: false,
8337                 onConfirm: function(){} */
8338         },
8339         initialize: function() {
8340                 var args = this.getArgs(arguments);
8341                 this.setOptions(args.options);
8342                 this.legacy();
8343                 var css = this.options.css.substitute({baseHref: this.options.baseHref || Clientcide.assetLocation + '/stickyWinHTML/'}, /\\?\{%([^}]+)%\}/g);
8344                 if (Browser.ie) css = css.replace(/png/g, 'gif');
8345                 this.createStyle(css, this.options.cssId);
8346                 this.build();
8347                 if (args.caption || args.body) this.setContent(args.caption, args.body);
8348         },
8349         toElement: function(){
8350                 return this.element;
8351         },
8352         getArgs: function(){
8353                 return StickyWin.UI.getArgs.apply(this, arguments);
8354         },
8355         legacy: function(){
8356                 var opt = this.options; //saving bytes
8357                 //legacy support
8358                 if (opt.confirmTxt) opt.buttons.push({text: opt.confirmTxt, onClick: opt.onConfirm || function(){}});
8359                 if (opt.closeTxt) opt.buttons.push({text: opt.closeTxt, onClick: opt.onClose || function(){}});
8360         },
8361         build: function(){
8362                 var opt = this.options;
8363
8364                 var container = new Element('div', {
8365                         'class': opt.cssClassName
8366                 });
8367                 if (opt.width) container.setStyle('width', opt.width);
8368                 this.element = container;
8369                 this.element.store('StickyWinUI', this);
8370                 if (opt.cssClass) container.addClass(opt.cssClass);
8371
8372
8373                 var bodyDiv = new Element('div').addClass('body');
8374                 this.body = bodyDiv;
8375
8376                 var top_ur = new Element('div').addClass('top_ur');
8377                 this.top_ur = top_ur;
8378                 this.top = new Element('div').addClass('top').adopt(
8379                                 new Element('div').addClass('top_ul')
8380                         ).adopt(top_ur);
8381                 container.adopt(this.top);
8382
8383                 if (opt.cornerHandle) new Element('div').addClass('dragHandle').inject(top_ur, 'top');
8384
8385                 //body
8386                 container.adopt(new Element('div').addClass('middle').adopt(bodyDiv));
8387                 //close buttons
8388                 if (opt.buttons.length > 0){
8389                         var closeButtons = new Element('div').addClass('closeButtons');
8390                         opt.buttons.each(function(button){
8391                                 if (button.properties && button.properties.className){
8392                                         button.properties['class'] = button.properties.className;
8393                                         delete button.properties.className;
8394                                 }
8395                                 var properties = Object.merge({'class': 'closeSticky'}, button.properties);
8396                                 new Element('a').addEvent('click', button.onClick || function(){})
8397                                         .appendText(button.text).inject(closeButtons).set(properties).addClass('button');
8398                         });
8399                         container.adopt(new Element('div').addClass('closeBody').adopt(closeButtons));
8400                 }
8401                 //footer
8402                 container.adopt(
8403                         new Element('div').addClass('bottom').adopt(
8404                                         new Element('div').addClass('bottom_ll')
8405                                 ).adopt(
8406                                         new Element('div').addClass('bottom_lr')
8407                         )
8408                 );
8409                 if (this.options.closeButton) container.adopt(new Element('div').addClass('closeButton').addClass('closeSticky'));
8410                 return this;
8411         },
8412         setCaption: function(caption) {
8413                 this.caption = caption;
8414                 if (!this.h1) {
8415                         this.makeCaption(caption);
8416                 } else {
8417                         if (document.id(caption)) this.h1.adopt(caption);
8418                         else this.h1.set('html', caption);
8419                 }
8420                 return this;
8421         },
8422         makeCaption: function(caption) {
8423                 if (!caption) return this.destroyCaption();
8424                 var opt = this.options;
8425                 this.h1 = new Element('h1').addClass('caption');
8426                 if (opt.width) this.h1.setStyle('width', (opt.width.toInt()-(opt.cornerHandle?55:40)-(opt.closeButton?10:0)));
8427                 this.setCaption(caption);
8428                 this.top_ur.adopt(this.h1);
8429                 if (!this.options.cornerHandle) this.h1.addClass('dragHandle');
8430                 return this;
8431         },
8432         destroyCaption: function(){
8433                 if (this.h1) {
8434                         this.h1.destroy();
8435                         this.h1 = null;
8436                 }
8437                 return this;
8438         },
8439         setContent: function(){
8440                 var args = this.getArgs.apply(this, arguments);
8441                 var caption = args.caption;
8442                 var body = args.body;
8443                 this.setCaption(caption);
8444                 if (document.id(body)) this.body.empty().adopt(body);
8445                 else this.body.set('html', body);
8446                 return this;
8447         }
8448 });
8449 StickyWin.UI.getArgs = function(){
8450         var input = typeOf(arguments[0]) == "arguments"?arguments[0]:arguments;
8451         if (Browser.opera && 1 === input.length) input = input[0];
8452
8453         var cap = input[0], bod = input[1];
8454         var args = Array.link(input, {options: Type.isObject});
8455         if (input.length == 3 || (!args.options && input.length == 2)) {
8456                 args.caption = cap;
8457                 args.body = bod;
8458         } else if ((typeOf(bod) == 'object' || !bod) && cap && typeOf(cap) != 'object'){
8459                 args.body = cap;
8460         }
8461         return args;
8462 };
8463
8464 StickyWin.ui = function(caption, body, options){
8465         return document.id(new StickyWin.UI(caption, body, options));
8466 };
8467
8468
8469 // Begin: Source/UI/StickyWin.Alert.js
8470 /*
8471 ---
8472
8473 name: StickyWin.Alert
8474
8475 description: Defines StickyWin.Alert, a simple little alert box with a close button.
8476
8477 license: MIT-Style License
8478
8479 requires: [StickyWin.Modal, StickyWin.UI]
8480
8481 provides: [StickyWin.Alert, StickyWin.Error, StickyWin.alert, StickyWin.error]
8482
8483 ...
8484 */
8485 StickyWin.Alert = new Class({
8486         Implements: Options,
8487         Extends: StickyWin.Modal,
8488         options: {
8489                 destroyOnClose: true,
8490                 modalOptions: {
8491                         modalStyle: {
8492                                 zIndex: 11000
8493                         }
8494                 },
8495                 zIndex: 110001,
8496                 uiOptions: {
8497                         width: 250,
8498                         buttons: [
8499                                 {text: 'Ok'}
8500                         ]
8501                 },
8502                 getWindowManager: function(){}
8503         },
8504         initialize: function(caption, message, options) {
8505                 this.message = message;
8506                 this.caption = caption;
8507                 this.setOptions(options);
8508                 this.setOptions({
8509                         content: this.build()
8510                 });
8511                 this.parent(options);
8512         },
8513         makeMessage: function() {
8514                 return new Element('p', {
8515                         'class': 'errorMsg SWclearfix',
8516                         styles: {
8517                                 margin: 0,
8518                                 minHeight: 10
8519                         },
8520                         html: this.message
8521                 });
8522         },
8523         build: function(){
8524                 return StickyWin.ui(this.caption, this.makeMessage(), this.options.uiOptions);
8525         }
8526 });
8527
8528 StickyWin.Error = new Class({
8529         Extends: StickyWin.Alert,
8530         makeMessage: function(){
8531                 var message = this.parent();
8532                 new Element('img', {
8533                         src: (this.options.baseHref || Clientcide.assetLocation + '/simple.error.popup') + '/icon_problems_sm.gif',
8534                         'class': 'bang clearfix',
8535                         styles: {
8536                                 'float': 'left',
8537                                 width: 30,
8538                                 height: 30,
8539                                 margin: '3px 5px 5px 0px'
8540                         }
8541                 }).inject(message, 'top');
8542                 return message;
8543         }
8544 });
8545
8546 StickyWin.alert = function(caption, message, options) {
8547         if (typeOf(options) == "string") options = {baseHref: options};
8548         return new StickyWin.Alert(caption, message, options);
8549 };
8550
8551 StickyWin.error = function(caption, message, options) {
8552         return new StickyWin.Error(caption, message, options);
8553 };
8554
8555 // Begin: Source/UI/StickyWin.Confirm.js
8556 /*
8557 ---
8558 name: StickyWin.Confirm
8559
8560 description: Defines StickyWin.Conferm, a simple confirmation box with an ok and a close button.
8561
8562 license: MIT-Style License
8563
8564 requires: StickyWin.Alert
8565
8566 provides: [StickyWin.Confirm, StickyWin.confirm]
8567
8568 ...
8569 */
8570 StickyWin.Confirm = new Class({
8571         Extends: StickyWin.Alert,
8572         options: {
8573                 uiOptions: {
8574                         width: 250
8575                 }
8576         },
8577         build: function(callback){
8578                 this.setOptions({
8579                         uiOptions: {
8580                                 buttons: [
8581                                         {text: 'Cancel'},
8582                                         {
8583                                                 text: 'Ok',
8584                                                 onClick: callback || function(){
8585                                                         this.fireEvent('confirm');
8586                                                 }.bind(this)
8587                                         }
8588                                 ]
8589                         }
8590                 });
8591                 return this.parent();
8592         }
8593 });
8594
8595 StickyWin.confirm = function(caption, message, callback, options) {
8596         return new StickyWin.Confirm(caption, message, options).addEvent('confirm', callback);
8597 };
8598
8599 // Begin: Source/Fx/Fx.Move.js
8600 /*
8601 ---
8602
8603 script: Fx.Move.js
8604
8605 name: Fx.Move
8606
8607 description: Defines Fx.Move, a class that works with Element.Position.js to transition an element from one location to another.
8608
8609 license: MIT-style license
8610
8611 authors:
8612   - Aaron Newton
8613
8614 requires:
8615   - Core/Fx.Morph
8616   - /Element.Position
8617
8618 provides: [Fx.Move]
8619
8620 ...
8621 */
8622
8623 Fx.Move = new Class({
8624
8625         Extends: Fx.Morph,
8626
8627         options: {
8628                 relativeTo: document.body,
8629                 position: 'center',
8630                 edge: false,
8631                 offset: {x: 0, y: 0}
8632         },
8633
8634         start: function(destination){
8635                 var element = this.element,
8636                         topLeft = element.getStyles('top', 'left');
8637                 if (topLeft.top == 'auto' || topLeft.left == 'auto'){
8638                         element.setPosition(element.getPosition(element.getOffsetParent()));
8639                 }
8640                 return this.parent(element.position(Object.merge({}, this.options, destination, {returnPos: true})));
8641         }
8642
8643 });
8644
8645 Element.Properties.move = {
8646
8647         set: function(options){
8648                 this.get('move').cancel().setOptions(options);
8649                 return this;
8650         },
8651
8652         get: function(){
8653                 var move = this.retrieve('move');
8654                 if (!move){
8655                         move = new Fx.Move(this, {link: 'cancel'});
8656                         this.store('move', move);
8657                 }
8658                 return move;
8659         }
8660
8661 };
8662
8663 Element.implement({
8664
8665         move: function(options){
8666                 this.get('move').start(options);
8667                 return this;
8668         }
8669
8670 });
8671
8672
8673 // Begin: Source/Fx/Fx.Scroll.js
8674 /*
8675 ---
8676
8677 script: Fx.Scroll.js
8678
8679 name: Fx.Scroll
8680
8681 description: Effect to smoothly scroll any element, including the window.
8682
8683 license: MIT-style license
8684
8685 authors:
8686   - Valerio Proietti
8687
8688 requires:
8689   - Core/Fx
8690   - Core/Element.Event
8691   - Core/Element.Dimensions
8692   - /MooTools.More
8693
8694 provides: [Fx.Scroll]
8695
8696 ...
8697 */
8698
8699 (function(){
8700
8701 Fx.Scroll = new Class({
8702
8703         Extends: Fx,
8704
8705         options: {
8706                 offset: {x: 0, y: 0},
8707                 wheelStops: true
8708         },
8709
8710         initialize: function(element, options){
8711                 this.element = this.subject = document.id(element);
8712                 this.parent(options);
8713
8714                 if (typeOf(this.element) != 'element') this.element = document.id(this.element.getDocument().body);
8715
8716                 if (this.options.wheelStops){
8717                         var stopper = this.element,
8718                                 cancel = this.cancel.pass(false, this);
8719                         this.addEvent('start', function(){
8720                                 stopper.addEvent('mousewheel', cancel);
8721                         }, true);
8722                         this.addEvent('complete', function(){
8723                                 stopper.removeEvent('mousewheel', cancel);
8724                         }, true);
8725                 }
8726         },
8727
8728         set: function(){
8729                 var now = Array.flatten(arguments);
8730                 if (Browser.firefox) now = [Math.round(now[0]), Math.round(now[1])]; // not needed anymore in newer firefox versions
8731                 this.element.scrollTo(now[0], now[1]);
8732                 return this;
8733         },
8734
8735         compute: function(from, to, delta){
8736                 return [0, 1].map(function(i){
8737                         return Fx.compute(from[i], to[i], delta);
8738                 });
8739         },
8740
8741         start: function(x, y){
8742                 if (!this.check(x, y)) return this;
8743                 var scroll = this.element.getScroll();
8744                 return this.parent([scroll.x, scroll.y], [x, y]);
8745         },
8746
8747         calculateScroll: function(x, y){
8748                 var element = this.element,
8749                         scrollSize = element.getScrollSize(),
8750                         scroll = element.getScroll(),
8751                         size = element.getSize(),
8752                         offset = this.options.offset,
8753                         values = {x: x, y: y};
8754
8755                 for (var z in values){
8756                         if (!values[z] && values[z] !== 0) values[z] = scroll[z];
8757                         if (typeOf(values[z]) != 'number') values[z] = scrollSize[z] - size[z];
8758                         values[z] += offset[z];
8759                 }
8760
8761                 return [values.x, values.y];
8762         },
8763
8764         toTop: function(){
8765                 return this.start.apply(this, this.calculateScroll(false, 0));
8766         },
8767
8768         toLeft: function(){
8769                 return this.start.apply(this, this.calculateScroll(0, false));
8770         },
8771
8772         toRight: function(){
8773                 return this.start.apply(this, this.calculateScroll('right', false));
8774         },
8775
8776         toBottom: function(){
8777                 return this.start.apply(this, this.calculateScroll(false, 'bottom'));
8778         },
8779
8780         toElement: function(el, axes){
8781                 axes = axes ? Array.from(axes) : ['x', 'y'];
8782                 var scroll = isBody(this.element) ? {x: 0, y: 0} : this.element.getScroll();
8783                 var position = Object.map(document.id(el).getPosition(this.element), function(value, axis){
8784                         return axes.contains(axis) ? value + scroll[axis] : false;
8785                 });
8786                 return this.start.apply(this, this.calculateScroll(position.x, position.y));
8787         },
8788
8789         toElementEdge: function(el, axes, offset){
8790                 axes = axes ? Array.from(axes) : ['x', 'y'];
8791                 el = document.id(el);
8792                 var to = {},
8793                         position = el.getPosition(this.element),
8794                         size = el.getSize(),
8795                         scroll = this.element.getScroll(),
8796                         containerSize = this.element.getSize(),
8797                         edge = {
8798                                 x: position.x + size.x,
8799                                 y: position.y + size.y
8800                         };
8801
8802                 ['x', 'y'].each(function(axis){
8803                         if (axes.contains(axis)){
8804                                 if (edge[axis] > scroll[axis] + containerSize[axis]) to[axis] = edge[axis] - containerSize[axis];
8805                                 if (position[axis] < scroll[axis]) to[axis] = position[axis];
8806                         }
8807                         if (to[axis] == null) to[axis] = scroll[axis];
8808                         if (offset && offset[axis]) to[axis] = to[axis] + offset[axis];
8809                 }, this);
8810
8811                 if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y);
8812                 return this;
8813         },
8814
8815         toElementCenter: function(el, axes, offset){
8816                 axes = axes ? Array.from(axes) : ['x', 'y'];
8817                 el = document.id(el);
8818                 var to = {},
8819                         position = el.getPosition(this.element),
8820                         size = el.getSize(),
8821                         scroll = this.element.getScroll(),
8822                         containerSize = this.element.getSize();
8823
8824                 ['x', 'y'].each(function(axis){
8825                         if (axes.contains(axis)){
8826                                 to[axis] = position[axis] - (containerSize[axis] - size[axis]) / 2;
8827                         }
8828                         if (to[axis] == null) to[axis] = scroll[axis];
8829                         if (offset && offset[axis]) to[axis] = to[axis] + offset[axis];
8830                 }, this);
8831
8832                 if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y);
8833                 return this;
8834         }
8835
8836 });
8837
8838 //<1.2compat>
8839 Fx.Scroll.implement({
8840         scrollToCenter: function(){
8841                 return this.toElementCenter.apply(this, arguments);
8842         },
8843         scrollIntoView: function(){
8844                 return this.toElementEdge.apply(this, arguments);
8845         }
8846 });
8847 //</1.2compat>
8848
8849 function isBody(element){
8850         return (/^(?:body|html)$/i).test(element.tagName);
8851 }
8852
8853 })();
8854
8855
8856 // Begin: Source/Class/Class.Refactor.js
8857 /*
8858 ---
8859
8860 script: Class.Refactor.js
8861
8862 name: Class.Refactor
8863
8864 description: Extends a class onto itself with new property, preserving any items attached to the class's namespace.
8865
8866 license: MIT-style license
8867
8868 authors:
8869   - Aaron Newton
8870
8871 requires:
8872   - Core/Class
8873   - /MooTools.More
8874
8875 # Some modules declare themselves dependent on Class.Refactor
8876 provides: [Class.refactor, Class.Refactor]
8877
8878 ...
8879 */
8880
8881 Class.refactor = function(original, refactors){
8882
8883         Object.each(refactors, function(item, name){
8884                 var origin = original.prototype[name];
8885                 origin = (origin && origin.$origin) || origin || function(){};
8886                 original.implement(name, (typeof item == 'function') ? function(){
8887                         var old = this.previous;
8888                         this.previous = origin;
8889                         var value = item.apply(this, arguments);
8890                         this.previous = old;
8891                         return value;
8892                 } : item);
8893         });
8894
8895         return original;
8896
8897 };
8898
8899
8900 // Begin: Source/Fx/Fx.Tween.js
8901 /*
8902 ---
8903
8904 name: Fx.Tween
8905
8906 description: Formerly Fx.Style, effect to transition any CSS property for an element.
8907
8908 license: MIT-style license.
8909
8910 requires: Fx.CSS
8911
8912 provides: [Fx.Tween, Element.fade, Element.highlight]
8913
8914 ...
8915 */
8916
8917 Fx.Tween = new Class({
8918
8919         Extends: Fx.CSS,
8920
8921         initialize: function(element, options){
8922                 this.element = this.subject = document.id(element);
8923                 this.parent(options);
8924         },
8925
8926         set: function(property, now){
8927                 if (arguments.length == 1){
8928                         now = property;
8929                         property = this.property || this.options.property;
8930                 }
8931                 this.render(this.element, property, now, this.options.unit);
8932                 return this;
8933         },
8934
8935         start: function(property, from, to){
8936                 if (!this.check(property, from, to)) return this;
8937                 var args = Array.flatten(arguments);
8938                 this.property = this.options.property || args.shift();
8939                 var parsed = this.prepare(this.element, this.property, args);
8940                 return this.parent(parsed.from, parsed.to);
8941         }
8942
8943 });
8944
8945 Element.Properties.tween = {
8946
8947         set: function(options){
8948                 this.get('tween').cancel().setOptions(options);
8949                 return this;
8950         },
8951
8952         get: function(){
8953                 var tween = this.retrieve('tween');
8954                 if (!tween){
8955                         tween = new Fx.Tween(this, {link: 'cancel'});
8956                         this.store('tween', tween);
8957                 }
8958                 return tween;
8959         }
8960
8961 };
8962
8963 Element.implement({
8964
8965         tween: function(property, from, to){
8966                 this.get('tween').start(property, from, to);
8967                 return this;
8968         },
8969
8970         fade: function(how){
8971                 var fade = this.get('tween'), method, args = ['opacity'].append(arguments), toggle;
8972                 if (args[1] == null) args[1] = 'toggle';
8973                 switch (args[1]){
8974                         case 'in': method = 'start'; args[1] = 1; break;
8975                         case 'out': method = 'start'; args[1] = 0; break;
8976                         case 'show': method = 'set'; args[1] = 1; break;
8977                         case 'hide': method = 'set'; args[1] = 0; break;
8978                         case 'toggle':
8979                                 var flag = this.retrieve('fade:flag', this.getStyle('opacity') == 1);
8980                                 method = 'start';
8981                                 args[1] = flag ? 0 : 1;
8982                                 this.store('fade:flag', !flag);
8983                                 toggle = true;
8984                         break;
8985                         default: method = 'start';
8986                 }
8987                 if (!toggle) this.eliminate('fade:flag');
8988                 fade[method].apply(fade, args);
8989                 var to = args[args.length - 1];
8990                 if (method == 'set' || to != 0) this.setStyle('visibility', to == 0 ? 'hidden' : 'visible');
8991                 else fade.chain(function(){
8992                         this.element.setStyle('visibility', 'hidden');
8993                         this.callChain();
8994                 });
8995                 return this;
8996         },
8997
8998         highlight: function(start, end){
8999                 if (!end){
9000                         end = this.retrieve('highlight:original', this.getStyle('background-color'));
9001                         end = (end == 'transparent') ? '#fff' : end;
9002                 }
9003                 var tween = this.get('tween');
9004                 tween.start('background-color', start || '#ffff88', end).chain(function(){
9005                         this.setStyle('background-color', this.retrieve('highlight:original'));
9006                         tween.callChain();
9007                 }.bind(this));
9008                 return this;
9009         }
9010
9011 });
9012
9013
9014 // Begin: Source/UI/StickyWin.Fx.js
9015 /*
9016 ---
9017
9018 name: StickyWin.Fx
9019
9020 description: Extends StickyWin to create popups that fade in and out.
9021
9022 license: MIT-style license.
9023
9024 requires: [More/Class.Refactor, Core/Fx.Tween, StickyWin]
9025
9026 provides: StickyWin.Fx
9027
9028 ...
9029 */
9030 if (!Browser.ie){
9031         StickyWin = Class.refactor(StickyWin, {
9032                 options: {
9033                         //fadeTransition: 'sine:in:out',
9034                         fade: true,
9035                         fadeDuration: 150
9036                 },
9037                 hideWin: function(){
9038                         if (this.options.fade) this.fade(0);
9039                         else this.previous();
9040                 },
9041                 showWin: function(){
9042                         if (this.options.fade) this.fade(1);
9043                         else this.previous();
9044                 },
9045                 hide: function(){
9046                         this.previous(this.options.fade);
9047                 },
9048                 show: function(){
9049                         this.previous(this.options.fade);
9050                 },
9051                 fade: function(to){
9052                         if (!this.fadeFx) {
9053                                 this.win.setStyles({
9054                                         opacity: 0,
9055                                         display: 'block'
9056                                 });
9057                                 var opts = {
9058                                         property: 'opacity',
9059                                         duration: this.options.fadeDuration
9060                                 };
9061                                 if (this.options.fadeTransition) opts.transition = this.options.fadeTransition;
9062                                 this.fadeFx = new Fx.Tween(this.win, opts);
9063                         }
9064                         if (to > 0) {
9065                                 this.win.setStyle('display','block');
9066                                 this.position();
9067                         }
9068                         this.fadeFx.clearChain();
9069                         this.fadeFx.start(to).chain(function (){
9070                                 if (to == 0) {
9071                                         this.win.setStyle('display', 'none');
9072                                         this.fireEvent('onClose');
9073                                 } else {
9074                                         this.fireEvent('onDisplay');
9075                                 }
9076                         }.bind(this));
9077                         return this;
9078                 }
9079         });
9080 }
9081 StickyWin.Fx = StickyWin;
9082
9083
9084 // Begin: Source/Types/Array.Extras.js
9085 /*
9086 ---
9087
9088 script: Array.Extras.js
9089
9090 name: Array.Extras
9091
9092 description: Extends the Array native object to include useful methods to work with arrays.
9093
9094 license: MIT-style license
9095
9096 authors:
9097   - Christoph Pojer
9098   - Sebastian Markbåge
9099
9100 requires:
9101   - Core/Array
9102   - MooTools.More
9103
9104 provides: [Array.Extras]
9105
9106 ...
9107 */
9108
9109 (function(nil){
9110
9111 Array.implement({
9112
9113         min: function(){
9114                 return Math.min.apply(null, this);
9115         },
9116
9117         max: function(){
9118                 return Math.max.apply(null, this);
9119         },
9120
9121         average: function(){
9122                 return this.length ? this.sum() / this.length : 0;
9123         },
9124
9125         sum: function(){
9126                 var result = 0, l = this.length;
9127                 if (l){
9128                         while (l--) result += this[l];
9129                 }
9130                 return result;
9131         },
9132
9133         unique: function(){
9134                 return [].combine(this);
9135         },
9136
9137         shuffle: function(){
9138                 for (var i = this.length; i && --i;){
9139                         var temp = this[i], r = Math.floor(Math.random() * ( i + 1 ));
9140                         this[i] = this[r];
9141                         this[r] = temp;
9142                 }
9143                 return this;
9144         },
9145
9146         reduce: function(fn, value){
9147                 for (var i = 0, l = this.length; i < l; i++){
9148                         if (i in this) value = value === nil ? this[i] : fn.call(null, value, this[i], i, this);
9149                 }
9150                 return value;
9151         },
9152
9153         reduceRight: function(fn, value){
9154                 var i = this.length;
9155                 while (i--){
9156                         if (i in this) value = value === nil ? this[i] : fn.call(null, value, this[i], i, this);
9157                 }
9158                 return value;
9159         },
9160
9161         pluck: function(prop){
9162                 return this.map(function(item){
9163                         return item[prop];
9164                 });
9165         }
9166
9167 });
9168
9169 })();
9170
9171
9172 // Begin: Source/Request/Request.HTML.js
9173 /*
9174 ---
9175
9176 name: Request.HTML
9177
9178 description: Extends the basic Request Class with additional methods for interacting with HTML responses.
9179
9180 license: MIT-style license.
9181
9182 requires: [Element, Request]
9183
9184 provides: Request.HTML
9185
9186 ...
9187 */
9188
9189 Request.HTML = new Class({
9190
9191         Extends: Request,
9192
9193         options: {
9194                 update: false,
9195                 append: false,
9196                 evalScripts: true,
9197                 filter: false,
9198                 headers: {
9199                         Accept: 'text/html, application/xml, text/xml, */*'
9200                 }
9201         },
9202
9203         success: function(text){
9204                 var options = this.options, response = this.response;
9205
9206                 response.html = text.stripScripts(function(script){
9207                         response.javascript = script;
9208                 });
9209
9210                 var match = response.html.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
9211                 if (match) response.html = match[1];
9212                 var temp = new Element('div').set('html', response.html);
9213
9214                 response.tree = temp.childNodes;
9215                 response.elements = temp.getElements(options.filter || '*');
9216
9217                 if (options.filter) response.tree = response.elements;
9218                 if (options.update){
9219                         var update = document.id(options.update).empty();
9220                         if (options.filter) update.adopt(response.elements);
9221                         else update.set('html', response.html);
9222                 } else if (options.append){
9223                         var append = document.id(options.append);
9224                         if (options.filter) response.elements.reverse().inject(append);
9225                         else append.adopt(temp.getChildren());
9226                 }
9227                 if (options.evalScripts) Browser.exec(response.javascript);
9228
9229                 this.onSuccess(response.tree, response.elements, response.html, response.javascript);
9230         }
9231
9232 });
9233
9234 Element.Properties.load = {
9235
9236         set: function(options){
9237                 var load = this.get('load').cancel();
9238                 load.setOptions(options);
9239                 return this;
9240         },
9241
9242         get: function(){
9243                 var load = this.retrieve('load');
9244                 if (!load){
9245                         load = new Request.HTML({data: this, link: 'cancel', update: this, method: 'get'});
9246                         this.store('load', load);
9247                 }
9248                 return load;
9249         }
9250
9251 };
9252
9253 Element.implement({
9254
9255         load: function(){
9256                 this.get('load').send(Array.link(arguments, {data: Type.isObject, url: Type.isString}));
9257                 return this;
9258         }
9259
9260 });
9261
9262
9263 // Begin: Source/Layout/TabSwapper.js
9264 /*
9265 ---
9266
9267 name: TabSwapper
9268
9269 description: Handles the scripting for a common UI layout; the tabbed box.
9270
9271 license: MIT-Style License
9272
9273 requires: [Core/Element.Event, Core/Fx.Tween, Core/Fx.Morph, Core/Element.Dimensions, More/Element.Shortcuts, More/Element.Measure]
9274
9275 provides: TabSwapper
9276
9277 ...
9278 */
9279 var TabSwapper = new Class({
9280         Implements: [Options, Events],
9281         options: {
9282                 // initPanel: null,
9283                 // smooth: false,
9284                 // smoothSize: false,
9285                 // maxSize: null,
9286                 // onActive: function(){},
9287                 // onActiveAfterFx: function(){},
9288                 // onBackground: function(){}
9289                 // cookieName: null,
9290                 preventDefault: true,
9291                 selectedClass: 'tabSelected',
9292                 mouseoverClass: 'tabOver',
9293                 deselectedClass: '',
9294                 rearrangeDOM: true,
9295                 effectOptions: {
9296                         duration: 500
9297                 },
9298                 cookieDays: 999
9299         },
9300         tabs: [],
9301         sections: [],
9302         clickers: [],
9303         sectionFx: [],
9304         initialize: function(options){
9305                 this.setOptions(options);
9306                 var prev = this.setup();
9307                 if (prev) return prev;
9308                 if (this.options.initPanel != null) this.show(this.options.initPanel);
9309                 else if (this.options.cookieName && this.recall()) this.show(this.recall().toInt());
9310                 else this.show(0);
9311
9312         },
9313         setup: function(){
9314                 var opt = this.options,
9315                     sections = $$(opt.sections),
9316                     tabs = $$(opt.tabs);
9317                 if (tabs[0] && tabs[0].retrieve('tabSwapper')) return tabs[0].retrieve('tabSwapper');
9318                 var clickers = $$(opt.clickers);
9319                 tabs.each(function(tab, index){
9320                         this.addTab(tab, sections[index], clickers[index], index);
9321                 }, this);
9322         },
9323         addTab: function(tab, section, clicker, index){
9324                 tab = document.id(tab); clicker = document.id(clicker); section = document.id(section);
9325                 //if the tab is already in the interface, just move it
9326                 if (this.tabs.indexOf(tab) >= 0 && tab.retrieve('tabbered')
9327                          && this.tabs.indexOf(tab) != index && this.options.rearrangeDOM) {
9328                         this.moveTab(this.tabs.indexOf(tab), index);
9329                         return this;
9330                 }
9331                 //if the index isn't specified, put the tab at the end
9332                 if (index == null) index = this.tabs.length;
9333                 //if this isn't the first item, and there's a tab
9334                 //already in the interface at the index 1 less than this
9335                 //insert this after that one
9336                 if (index > 0 && this.tabs[index-1] && this.options.rearrangeDOM) {
9337                         tab.inject(this.tabs[index-1], 'after');
9338                         section.inject(this.tabs[index-1].retrieve('section'), 'after');
9339                 }
9340                 this.tabs.splice(index, 0, tab);
9341                 clicker = clicker || tab;
9342
9343                 tab.addEvents({
9344                         mouseout: function(){
9345                                 tab.removeClass(this.options.mouseoverClass);
9346                         }.bind(this),
9347                         mouseover: function(){
9348                                 tab.addClass(this.options.mouseoverClass);
9349                         }.bind(this)
9350                 });
9351
9352                 clicker.addEvent('click', function(e){
9353                         if (this.options.preventDefault) e.preventDefault();
9354                         this.show(index);
9355                 }.bind(this));
9356
9357                 tab.store('tabbered', true);
9358                 tab.store('section', section);
9359                 tab.store('clicker', clicker);
9360                 this.hideSection(index);
9361                 return this;
9362         },
9363         removeTab: function(index){
9364                 var now = this.tabs[this.now];
9365                 if (this.now == index){
9366                         if (index > 0) this.show(index - 1);
9367                         else if (index < this.tabs.length) this.show(index + 1);
9368                 }
9369                 this.now = this.tabs.indexOf(now);
9370                 return this;
9371         },
9372         moveTab: function(from, to){
9373                 var tab = this.tabs[from];
9374                 var clicker = tab.retrieve('clicker');
9375                 var section = tab.retrieve('section');
9376
9377                 var toTab = this.tabs[to];
9378                 var toClicker = toTab.retrieve('clicker');
9379                 var toSection = toTab.retrieve('section');
9380
9381                 this.tabs.erase(tab).splice(to, 0, tab);
9382
9383                 tab.inject(toTab, 'before');
9384                 clicker.inject(toClicker, 'before');
9385                 section.inject(toSection, 'before');
9386                 return this;
9387         },
9388         show: function(i){
9389                 if (this.now == null) {
9390                         this.tabs.each(function(tab, idx){
9391                                 if (i != idx)
9392                                         this.hideSection(idx);
9393                         }, this);
9394                 }
9395                 this.showSection(i).save(i);
9396                 return this;
9397         },
9398         save: function(index){
9399                 if (this.options.cookieName)
9400                         Cookie.write(this.options.cookieName, index, {duration:this.options.cookieDays});
9401                 return this;
9402         },
9403         recall: function(){
9404                 return (this.options.cookieName) ? Cookie.read(this.options.cookieName) : false;
9405         },
9406         hideSection: function(idx) {
9407                 var tab = this.tabs[idx];
9408                 if (!tab) return this;
9409                 var sect = tab.retrieve('section');
9410                 if (!sect) return this;
9411                 if (sect.getStyle('display') != 'none') {
9412                         this.lastHeight = sect.getSize().y;
9413                         sect.setStyle('display', 'none');
9414                         tab.swapClass(this.options.selectedClass, this.options.deselectedClass);
9415                         this.fireEvent('onBackground', [idx, sect, tab]);
9416                 }
9417                 return this;
9418         },
9419         showSection: function(idx) {
9420                 var tab = this.tabs[idx];
9421                 if (!tab) return this;
9422                 var sect = tab.retrieve('section');
9423                 if (!sect) return this;
9424                 var smoothOk = this.options.smooth && !Browser.ie;
9425                 if (this.now != idx) {
9426                         if (!tab.retrieve('tabFx'))
9427                                 tab.store('tabFx', new Fx.Morph(sect, this.options.effectOptions));
9428                         var overflow = sect.getStyle('overflow');
9429                         var start = {
9430                                 display:'block',
9431                                 overflow: 'hidden'
9432                         };
9433                         if (smoothOk) start.opacity = 0;
9434                         var effect = false;
9435                         if (smoothOk) {
9436                                 effect = {opacity: 1};
9437                         } else if (sect.getStyle('opacity').toInt() < 1) {
9438                                 sect.setStyle('opacity', 1);
9439                                 if (!this.options.smoothSize) this.fireEvent('onActiveAfterFx', [idx, sect, tab]);
9440                         }
9441                         if (this.options.smoothSize) {
9442                                 var size = sect.getDimensions().height;
9443                                 if (this.options.maxSize != null && this.options.maxSize < size)
9444                                         size = this.options.maxSize;
9445                                 if (!effect) effect = {};
9446                                 effect.height = size;
9447                         }
9448                         if (this.now != null) this.hideSection(this.now);
9449                         if (this.options.smoothSize && this.lastHeight) start.height = this.lastHeight;
9450                         sect.setStyles(start);
9451                         var finish = function(){
9452                                 this.fireEvent('onActiveAfterFx', [idx, sect, tab]);
9453                                 sect.setStyles({
9454                                         height: this.options.maxSize == effect.height ? this.options.maxSize : "auto",
9455                                         overflow: overflow
9456                                 });
9457                                 sect.getElements('input, textarea').setStyle('opacity', 1);
9458                         }.bind(this);
9459                         if (effect) {
9460                                 tab.retrieve('tabFx').start(effect).chain(finish);
9461                         } else {
9462                                 finish();
9463                         }
9464                         this.now = idx;
9465                         this.fireEvent('onActive', [idx, sect, tab]);
9466                 }
9467                 tab.swapClass(this.options.deselectedClass, this.options.selectedClass);
9468                 return this;
9469         }
9470 });
9471
9472
9473 // Begin: Source/Element/Element.Forms.js
9474 /*
9475 ---
9476
9477 script: Element.Forms.js
9478
9479 name: Element.Forms
9480
9481 description: Extends the Element native object to include methods useful in managing inputs.
9482
9483 license: MIT-style license
9484
9485 authors:
9486   - Aaron Newton
9487
9488 requires:
9489   - Core/Element
9490   - /String.Extras
9491   - /MooTools.More
9492
9493 provides: [Element.Forms]
9494
9495 ...
9496 */
9497
9498 Element.implement({
9499
9500         tidy: function(){
9501                 this.set('value', this.get('value').tidy());
9502         },
9503
9504         getTextInRange: function(start, end){
9505                 return this.get('value').substring(start, end);
9506         },
9507
9508         getSelectedText: function(){
9509                 if (this.setSelectionRange) return this.getTextInRange(this.getSelectionStart(), this.getSelectionEnd());
9510                 return document.selection.createRange().text;
9511         },
9512
9513         getSelectedRange: function(){
9514                 if (this.selectionStart != null){
9515                         return {
9516                                 start: this.selectionStart,
9517                                 end: this.selectionEnd
9518                         };
9519                 }
9520
9521                 var pos = {
9522                         start: 0,
9523                         end: 0
9524                 };
9525                 var range = this.getDocument().selection.createRange();
9526                 if (!range || range.parentElement() != this) return pos;
9527                 var duplicate = range.duplicate();
9528
9529                 if (this.type == 'text'){
9530                         pos.start = 0 - duplicate.moveStart('character', -100000);
9531                         pos.end = pos.start + range.text.length;
9532                 } else {
9533                         var value = this.get('value');
9534                         var offset = value.length;
9535                         duplicate.moveToElementText(this);
9536                         duplicate.setEndPoint('StartToEnd', range);
9537                         if (duplicate.text.length) offset -= value.match(/[\n\r]*$/)[0].length;
9538                         pos.end = offset - duplicate.text.length;
9539                         duplicate.setEndPoint('StartToStart', range);
9540                         pos.start = offset - duplicate.text.length;
9541                 }
9542                 return pos;
9543         },
9544
9545         getSelectionStart: function(){
9546                 return this.getSelectedRange().start;
9547         },
9548
9549         getSelectionEnd: function(){
9550                 return this.getSelectedRange().end;
9551         },
9552
9553         setCaretPosition: function(pos){
9554                 if (pos == 'end') pos = this.get('value').length;
9555                 this.selectRange(pos, pos);
9556                 return this;
9557         },
9558
9559         getCaretPosition: function(){
9560                 return this.getSelectedRange().start;
9561         },
9562
9563         selectRange: function(start, end){
9564                 if (this.setSelectionRange){
9565                         this.focus();
9566                         this.setSelectionRange(start, end);
9567                 } else {
9568                         var value = this.get('value');
9569                         var diff = value.substr(start, end - start).replace(/\r/g, '').length;
9570                         start = value.substr(0, start).replace(/\r/g, '').length;
9571                         var range = this.createTextRange();
9572                         range.collapse(true);
9573                         range.moveEnd('character', start + diff);
9574                         range.moveStart('character', start);
9575                         range.select();
9576                 }
9577                 return this;
9578         },
9579
9580         insertAtCursor: function(value, select){
9581                 var pos = this.getSelectedRange();
9582                 var text = this.get('value');
9583                 this.set('value', text.substring(0, pos.start) + value + text.substring(pos.end, text.length));
9584                 if (select !== false) this.selectRange(pos.start, pos.start + value.length);
9585                 else this.setCaretPosition(pos.start + value.length);
9586                 return this;
9587         },
9588
9589         insertAroundCursor: function(options, select){
9590                 options = Object.append({
9591                         before: '',
9592                         defaultMiddle: '',
9593                         after: ''
9594                 }, options);
9595
9596                 var value = this.getSelectedText() || options.defaultMiddle;
9597                 var pos = this.getSelectedRange();
9598                 var text = this.get('value');
9599
9600                 if (pos.start == pos.end){
9601                         this.set('value', text.substring(0, pos.start) + options.before + value + options.after + text.substring(pos.end, text.length));
9602                         this.selectRange(pos.start + options.before.length, pos.end + options.before.length + value.length);
9603                 } else {
9604                         var current = text.substring(pos.start, pos.end);
9605                         this.set('value', text.substring(0, pos.start) + options.before + current + options.after + text.substring(pos.end, text.length));
9606                         var selStart = pos.start + options.before.length;
9607                         if (select !== false) this.selectRange(selStart, selStart + current.length);
9608                         else this.setCaretPosition(selStart + text.length);
9609                 }
9610                 return this;
9611         }
9612
9613 });
9614
9615
9616 // Begin: Source/Fx/Fx.Reveal.js
9617 /*
9618 ---
9619
9620 script: Fx.Reveal.js
9621
9622 name: Fx.Reveal
9623
9624 description: Defines Fx.Reveal, a class that shows and hides elements with a transition.
9625
9626 license: MIT-style license
9627
9628 authors:
9629   - Aaron Newton
9630
9631 requires:
9632   - Core/Fx.Morph
9633   - /Element.Shortcuts
9634   - /Element.Measure
9635
9636 provides: [Fx.Reveal]
9637
9638 ...
9639 */
9640
9641 (function(){
9642
9643
9644 var hideTheseOf = function(object){
9645         var hideThese = object.options.hideInputs;
9646         if (window.OverText){
9647                 var otClasses = [null];
9648                 OverText.each(function(ot){
9649                         otClasses.include('.' + ot.options.labelClass);
9650                 });
9651                 if (otClasses) hideThese += otClasses.join(', ');
9652         }
9653         return (hideThese) ? object.element.getElements(hideThese) : null;
9654 };
9655
9656
9657 Fx.Reveal = new Class({
9658
9659         Extends: Fx.Morph,
9660
9661         options: {/*
9662                 onShow: function(thisElement){},
9663                 onHide: function(thisElement){},
9664                 onComplete: function(thisElement){},
9665                 heightOverride: null,
9666                 widthOverride: null,*/
9667                 link: 'cancel',
9668                 styles: ['padding', 'border', 'margin'],
9669                 transitionOpacity: !Browser.ie6,
9670                 mode: 'vertical',
9671                 display: function(){
9672                         return this.element.get('tag') != 'tr' ? 'block' : 'table-row';
9673                 },
9674                 opacity: 1,
9675                 hideInputs: Browser.ie ? 'select, input, textarea, object, embed' : null
9676         },
9677
9678         dissolve: function(){
9679                 if (!this.hiding && !this.showing){
9680                         if (this.element.getStyle('display') != 'none'){
9681                                 this.hiding = true;
9682                                 this.showing = false;
9683                                 this.hidden = true;
9684                                 this.cssText = this.element.style.cssText;
9685
9686                                 var startStyles = this.element.getComputedSize({
9687                                         styles: this.options.styles,
9688                                         mode: this.options.mode
9689                                 });
9690                                 if (this.options.transitionOpacity) startStyles.opacity = this.options.opacity;
9691
9692                                 var zero = {};
9693                                 Object.each(startStyles, function(style, name){
9694                                         zero[name] = [style, 0];
9695                                 });
9696
9697                                 this.element.setStyles({
9698                                         display: Function.from(this.options.display).call(this),
9699                                         overflow: 'hidden'
9700                                 });
9701
9702                                 var hideThese = hideTheseOf(this);
9703                                 if (hideThese) hideThese.setStyle('visibility', 'hidden');
9704
9705                                 this.$chain.unshift(function(){
9706                                         if (this.hidden){
9707                                                 this.hiding = false;
9708                                                 this.element.style.cssText = this.cssText;
9709                                                 this.element.setStyle('display', 'none');
9710                                                 if (hideThese) hideThese.setStyle('visibility', 'visible');
9711                                         }
9712                                         this.fireEvent('hide', this.element);
9713                                         this.callChain();
9714                                 }.bind(this));
9715
9716                                 this.start(zero);
9717                         } else {
9718                                 this.callChain.delay(10, this);
9719                                 this.fireEvent('complete', this.element);
9720                                 this.fireEvent('hide', this.element);
9721                         }
9722                 } else if (this.options.link == 'chain'){
9723                         this.chain(this.dissolve.bind(this));
9724                 } else if (this.options.link == 'cancel' && !this.hiding){
9725                         this.cancel();
9726                         this.dissolve();
9727                 }
9728                 return this;
9729         },
9730
9731         reveal: function(){
9732                 if (!this.showing && !this.hiding){
9733                         if (this.element.getStyle('display') == 'none'){
9734                                 this.hiding = false;
9735                                 this.showing = true;
9736                                 this.hidden = false;
9737                                 this.cssText = this.element.style.cssText;
9738
9739                                 var startStyles;
9740                                 this.element.measure(function(){
9741                                         startStyles = this.element.getComputedSize({
9742                                                 styles: this.options.styles,
9743                                                 mode: this.options.mode
9744                                         });
9745                                 }.bind(this));
9746                                 if (this.options.heightOverride != null) startStyles.height = this.options.heightOverride.toInt();
9747                                 if (this.options.widthOverride != null) startStyles.width = this.options.widthOverride.toInt();
9748                                 if (this.options.transitionOpacity){
9749                                         this.element.setStyle('opacity', 0);
9750                                         startStyles.opacity = this.options.opacity;
9751                                 }
9752
9753                                 var zero = {
9754                                         height: 0,
9755                                         display: Function.from(this.options.display).call(this)
9756                                 };
9757                                 Object.each(startStyles, function(style, name){
9758                                         zero[name] = 0;
9759                                 });
9760                                 zero.overflow = 'hidden';
9761
9762                                 this.element.setStyles(zero);
9763
9764                                 var hideThese = hideTheseOf(this);
9765                                 if (hideThese) hideThese.setStyle('visibility', 'hidden');
9766
9767                                 this.$chain.unshift(function(){
9768                                         this.element.style.cssText = this.cssText;
9769                                         this.element.setStyle('display', Function.from(this.options.display).call(this));
9770                                         if (!this.hidden) this.showing = false;
9771                                         if (hideThese) hideThese.setStyle('visibility', 'visible');
9772                                         this.callChain();
9773                                         this.fireEvent('show', this.element);
9774                                 }.bind(this));
9775
9776                                 this.start(startStyles);
9777                         } else {
9778                                 this.callChain();
9779                                 this.fireEvent('complete', this.element);
9780                                 this.fireEvent('show', this.element);
9781                         }
9782                 } else if (this.options.link == 'chain'){
9783                         this.chain(this.reveal.bind(this));
9784                 } else if (this.options.link == 'cancel' && !this.showing){
9785                         this.cancel();
9786                         this.reveal();
9787                 }
9788                 return this;
9789         },
9790
9791         toggle: function(){
9792                 if (this.element.getStyle('display') == 'none'){
9793                         this.reveal();
9794                 } else {
9795                         this.dissolve();
9796                 }
9797                 return this;
9798         },
9799
9800         cancel: function(){
9801                 this.parent.apply(this, arguments);
9802                 if (this.cssText != null) this.element.style.cssText = this.cssText;
9803                 this.hiding = false;
9804                 this.showing = false;
9805                 return this;
9806         }
9807
9808 });
9809
9810 Element.Properties.reveal = {
9811
9812         set: function(options){
9813                 this.get('reveal').cancel().setOptions(options);
9814                 return this;
9815         },
9816
9817         get: function(){
9818                 var reveal = this.retrieve('reveal');
9819                 if (!reveal){
9820                         reveal = new Fx.Reveal(this);
9821                         this.store('reveal', reveal);
9822                 }
9823                 return reveal;
9824         }
9825
9826 };
9827
9828 Element.Properties.dissolve = Element.Properties.reveal;
9829
9830 Element.implement({
9831
9832         reveal: function(options){
9833                 this.get('reveal').setOptions(options).reveal();
9834                 return this;
9835         },
9836
9837         dissolve: function(options){
9838                 this.get('reveal').setOptions(options).dissolve();
9839                 return this;
9840         },
9841
9842         nix: function(options){
9843                 var params = Array.link(arguments, {destroy: Type.isBoolean, options: Type.isObject});
9844                 this.get('reveal').setOptions(options).dissolve().chain(function(){
9845                         this[params.destroy ? 'destroy' : 'dispose']();
9846                 }.bind(this));
9847                 return this;
9848         },
9849
9850         wink: function(){
9851                 var params = Array.link(arguments, {duration: Type.isNumber, options: Type.isObject});
9852                 var reveal = this.get('reveal').setOptions(params.options);
9853                 reveal.reveal().chain(function(){
9854                         (function(){
9855                                 reveal.dissolve();
9856                         }).delay(params.duration || 2000);
9857                 });
9858         }
9859
9860 });
9861
9862 })();
9863
9864
9865 // Begin: Source/Layout/Collapsible.js
9866 /*
9867 ---
9868 name: Collapsible
9869
9870 description: Enables a dom element to, when clicked, hide or show (it toggles) another dom element. Kind of an Accordion for one item.
9871
9872 license: MIT-Style License
9873
9874 requires: [Core/Element.Event, More/Fx.Reveal]
9875
9876 provides: Collapsible
9877 ...
9878 */
9879 var Collapsible = new Class({
9880         Extends: Fx.Reveal,
9881         initialize: function(clicker, section, options) {
9882                 this.clicker = document.id(clicker);
9883                 this.section = document.id(section);
9884                 this.parent(this.section, options);
9885                 this.boundtoggle = this.toggle.bind(this);
9886                 this.attach();
9887         },
9888         attach: function(){
9889                 this.clicker.addEvent('click', this.boundtoggle);
9890         },
9891         detach: function(){
9892                 this.clicker.removeEvent('click', this.boundtoggle);
9893         }
9894 });
9895 //legacy, this class originated w/ a typo. nice!
9896 var Collapsable = Collapsible;
9897
9898 // Begin: Source/Utilities/Table.js
9899 /*
9900 ---
9901 name: Table
9902 description: LUA-Style table implementation.
9903 license: MIT-style license
9904 authors:
9905   - Valerio Proietti
9906 requires: [Core/Array]
9907 provides: [Table]
9908 ...
9909 */
9910
9911 (function(){
9912
9913 var Table = this.Table = function(){
9914
9915         this.length = 0;
9916         var keys = [],
9917             values = [];
9918         
9919         this.set = function(key, value){
9920                 var index = keys.indexOf(key);
9921                 if (index == -1){
9922                         var length = keys.length;
9923                         keys[length] = key;
9924                         values[length] = value;
9925                         this.length++;
9926                 } else {
9927                         values[index] = value;
9928                 }
9929                 return this;
9930         };
9931
9932         this.get = function(key){
9933                 var index = keys.indexOf(key);
9934                 return (index == -1) ? null : values[index];
9935         };
9936
9937         this.erase = function(key){
9938                 var index = keys.indexOf(key);
9939                 if (index != -1){
9940                         this.length--;
9941                         keys.splice(index, 1);
9942                         return values.splice(index, 1)[0];
9943                 }
9944                 return null;
9945         };
9946
9947         this.each = this.forEach = function(fn, bind){
9948                 for (var i = 0, l = this.length; i < l; i++) fn.call(bind, keys[i], values[i], this);
9949         };
9950         
9951 };
9952
9953 if (this.Type) new Type('Table', Table);
9954
9955 })();
9956
9957
9958 // Begin: Source/Element.Data.js
9959 /*
9960 ---
9961 name: Element.Data
9962 description: Stores data in HTML5 data properties
9963 provides: [Element.Data]
9964 requires: [Core/Element, Core/JSON]
9965 script: Element.Data.js
9966
9967 ...
9968 */
9969 (function(){
9970
9971         JSON.isSecure = function(string){
9972                 //this verifies that the string is parsable JSON and not malicious (borrowed from JSON.js in MooTools, which in turn borrowed it from Crockford)
9973                 //this version is a little more permissive, as it allows single quoted attributes because forcing the use of double quotes
9974                 //is a pain when this stuff is used as HTML properties
9975                 return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '').replace(/'[^'\\\n\r]*'/g, ''));
9976         };
9977
9978         Element.implement({
9979                 /*
9980                         sets an HTML5 data property.
9981                         arguments:
9982                                 name - (string) the data name to store; will be automatically prefixed with 'data-'.
9983                                 value - (string, number) the value to store.
9984                 */
9985                 setData: function(name, value){
9986                         return this.set('data-' + name.hyphenate(), value);
9987                 },
9988
9989                 getData: function(name, defaultValue){
9990                         var value = this.get('data-' + name.hyphenate());
9991                         if (value != undefined){
9992                                 return value;
9993                         } else if (defaultValue != undefined){
9994                                 this.setData(name, defaultValue);
9995                                 return defaultValue;
9996                         }
9997                 },
9998
9999                 /* 
10000                         arguments:
10001                                 name - (string) the data name to store; will be automatically prefixed with 'data-'
10002                                 value - (string, array, or object) if an object or array the object will be JSON encoded; otherwise stored as provided.
10003                 */
10004                 setJSONData: function(name, value){
10005                         return this.setData(name, JSON.encode(value));
10006                 },
10007
10008                 /*
10009                         retrieves a property from HTML5 data property you specify
10010                 
10011                         arguments:
10012                                 name - (retrieve) the data name to store; will be automatically prefixed with 'data-'
10013                                 strict - (boolean) if true, will set the JSON.decode's secure flag to true; otherwise the value is still tested but allows single quoted attributes.
10014                                 defaultValue - (string, array, or object) the value to set if no value is found (see storeData above)
10015                 */
10016                 getJSONData: function(name, strict, defaultValue){
10017                         var value = this.get('data-' + name);
10018                         if (value != undefined){
10019                                 if (value && JSON.isSecure(value)) {
10020                                         return JSON.decode(value, strict);
10021                                 } else {
10022                                         return value;
10023                                 }
10024                         } else if (defaultValue != undefined){
10025                                 this.setJSONData(name, defaultValue);
10026                                 return defaultValue;
10027                         }
10028                 }
10029
10030         });
10031
10032 })();
10033
10034 // Begin: Source/BehaviorAPI.js
10035 /*
10036 ---
10037 name: BehaviorAPI
10038 description: HTML getters for Behavior's API model.
10039 requires: [Core/Class, /Element.Data]
10040 provides: [BehaviorAPI]
10041 ...
10042 */
10043
10044
10045 (function(){
10046         //see Docs/BehaviorAPI.md for documentation of public methods.
10047
10048         var reggy = /[^a-z0-9\-]/gi;
10049
10050         window.BehaviorAPI = new Class({
10051                 element: null,
10052                 prefix: '',
10053                 defaults: {},
10054
10055                 initialize: function(element, prefix){
10056                         this.element = element;
10057                         this.prefix = prefix.toLowerCase().replace('.', '-', 'g').replace(reggy, '');
10058                 },
10059
10060                 /******************
10061                  * PUBLIC METHODS
10062                  ******************/
10063
10064                 get: function(/* name[, name, name, etc] */){
10065                         if (arguments.length > 1) return this._getObj(Array.from(arguments));
10066                         return this._getValue(arguments[0]);
10067                 },
10068
10069                 getAs: function(/*returnType, name, defaultValue OR {name: returnType, name: returnType, etc}*/){
10070                         if (typeOf(arguments[0]) == 'object') return this._getValuesAs.apply(this, arguments);
10071                         return this._getValueAs.apply(this, arguments);
10072                 },
10073
10074                 require: function(/* name[, name, name, etc] */){
10075                         for (var i = 0; i < arguments.length; i++){
10076                                 if (this._getValue(arguments[i]) == undefined) throw new Error('Could not retrieve ' + this.prefix + '-' + arguments[i] + ' option from element.');
10077                         }
10078                         return this;
10079                 },
10080
10081                 requireAs: function(returnType, name /* OR {name: returnType, name: returnType, etc}*/){
10082                         var val;
10083                         if (typeOf(arguments[0]) == 'object'){
10084                                 for (var objName in arguments[0]){
10085                                         val = this._getValueAs(arguments[0][objName], objName);
10086                                         if (val === undefined || val === null) throw new Error("Could not retrieve " + this.prefix + '-' + objName + " option from element.");
10087                                 }
10088                         } else {
10089                                 val = this._getValueAs(returnType, name);
10090                                 if (val === undefined || val === null) throw new Error("Could not retrieve " + this.prefix + '-' + name + " option from element.");
10091                         }
10092                         return this;
10093                 },
10094
10095                 setDefault: function(name, value /* OR {name: value, name: value, etc }*/){
10096                         if (typeOf(arguments[0]) == 'object'){
10097                                 for (var objName in arguments[0]){
10098                                         this.setDefault(objName, arguments[0][objName]);
10099                                 }
10100                                 return;
10101                         }
10102                         name = name.camelCase();
10103                         this.defaults[name] = value;
10104                         if (this._getValue(name) == null){
10105                                 var options = this._getOptions();
10106                                 options[name] = value;
10107                         }
10108                         return this;
10109                 },
10110
10111                 refreshAPI: function(){
10112                         delete this.options;
10113                         this.setDefault(this.defaults);
10114                         return;
10115                 },
10116
10117                 /******************
10118                  * PRIVATE METHODS
10119                  ******************/
10120
10121                 //given an array of names, returns an object of key/value pairs for each name
10122                 _getObj: function(names){
10123                         var obj = {};
10124                         names.each(function(name){
10125                                 var value = this._getValue(name);
10126                                 if (value !== undefined) obj[name] = value;
10127                         }, this);
10128                         return obj;
10129                 },
10130                 //gets the data-behaviorname-options object and parses it as JSON
10131                 _getOptions: function(){
10132                         try {
10133                                 if (!this.options){
10134                                         var options = this.element.getData(this.prefix + '-options', '{}');
10135                                         if (options && options.substring(0,1) != '{') options = '{' + options + '}';
10136                                         var isSecure = JSON.isSecure(options);
10137                                         if (!isSecure) throw new Error('warning, options value for element is not parsable, check your JSON format for quotes, etc.');
10138                                         this.options = isSecure ? JSON.decode(options) : {};
10139                                         for (option in this.options) {
10140                                                 this.options[option.camelCase()] = this.options[option];
10141                                         }
10142                                 }
10143                         } catch (e){
10144                                 throw new Error('Could not get options from element; check your syntax. ' + this.prefix + '-options: "' + this.element.getData(this.prefix + '-options', '{}') + '"');
10145                         }
10146                         return this.options;
10147                 },
10148                 //given a name (string) returns the value for it
10149                 _getValue: function(name){
10150                         name = name.camelCase();
10151                         var options = this._getOptions();
10152                         if (!options.hasOwnProperty(name)){
10153                                 var inline = this.element.getData(this.prefix + '-' + name.hyphenate());
10154                                 if (inline) options[name] = inline;
10155                         }
10156                         return options[name];
10157                 },
10158                 //given a Type and a name (string) returns the value for it coerced to that type if possible
10159                 //else returns the defaultValue or null
10160                 _getValueAs: function(returnType, name, defaultValue){
10161                         var value = this._getValue(name);
10162                         if (value == null || value == undefined) return defaultValue;
10163                         var coerced = this._coerceFromString(returnType, value);
10164                         if (coerced == null) throw new Error("Could not retrieve value '" + name + "' as the specified type. Its value is: " + value);
10165                         return coerced;
10166                 },
10167                 //given an object of name/Type pairs, returns those as an object of name/value (as specified Type) pairs
10168                 _getValuesAs: function(obj){
10169                         var returnObj = {};
10170                         for (var name in obj){
10171                                 returnObj[name] = this._getValueAs(obj[name], name);
10172                         }
10173                         return returnObj;
10174                 },
10175                 //attempts to run a value through the JSON parser. If the result is not of that type returns null.
10176                 _coerceFromString: function(toType, value){
10177                         if (typeOf(value) == 'string' && toType != String){
10178                                 if (JSON.isSecure(value)) value = JSON.decode(value);
10179                         }
10180                         if (instanceOf(value, toType)) return value;
10181                         return null;
10182                 }
10183         });
10184
10185 })();
10186
10187 // Begin: Source/Behavior.js
10188 /*
10189 ---
10190 name: Behavior
10191 description: Auto-instantiates widgets/classes based on parsed, declarative HTML.
10192 requires: [Core/Class.Extras, Core/Element.Event, Core/Selectors, More/Table, /Element.Data, /BehaviorAPI]
10193 provides: [Behavior]
10194 ...
10195 */
10196
10197 (function(){
10198
10199         var getLog = function(method){
10200                 return function(){
10201                         if (window.console && console[method]){
10202                                 if(console[method].apply) console[method].apply(console, arguments);
10203                                 else console[method](Array.from(arguments).join(' '));
10204                         }
10205                 };
10206         };
10207
10208         var PassMethods = new Class({
10209                 //pass a method pointer through to a filter
10210                 //by default the methods for add/remove events are passed to the filter
10211                 //pointed to this instance of behavior. you could use this to pass along
10212                 //other methods to your filters. For example, a method to close a popup
10213                 //for filters presented inside popups.
10214                 passMethod: function(method, fn){
10215                         if (this.API.prototype[method]) throw new Error('Cannot overwrite API method ' + method + ' as it already exists');
10216                         this.API.implement(method, fn);
10217                         return this;
10218                 },
10219
10220                 passMethods: function(methods){
10221                         for (method in methods) this.passMethod(method, methods[method]);
10222                         return this;
10223                 }
10224
10225         });
10226
10227         var spaceOrCommaRegex = /\s*,\s*|\s+/g;
10228
10229         BehaviorAPI.implement({
10230                 deprecate: function(deprecated, asJSON){
10231                         var set,
10232                             values = {};
10233                         Object.each(deprecated, function(prop, key){
10234                                 var value = this.element[ asJSON ? 'getJSONData' : 'getData'](prop);
10235                                 if (value !== undefined){
10236                                         set = true;
10237                                         values[key] = value;
10238                                 }
10239                         }, this);
10240                         this.setDefault(values);
10241                         return this;
10242                 }
10243         });
10244
10245         this.Behavior = new Class({
10246
10247                 Implements: [Options, Events, PassMethods],
10248
10249                 options: {
10250                         //by default, errors thrown by filters are caught; the onError event is fired.
10251                         //set this to *true* to NOT catch these errors to allow them to be handled by the browser.
10252                         // breakOnErrors: false,
10253                         // container: document.body,
10254
10255                         //default error behavior when a filter cannot be applied
10256                         onError: getLog('error'),
10257                         onWarn: getLog('warn'),
10258                         enableDeprecation: true,
10259                         selector: '[data-behavior]'
10260                 },
10261
10262                 initialize: function(options){
10263                         this.setOptions(options);
10264                         this.API = new Class({ Extends: BehaviorAPI });
10265                         this.passMethods({
10266                                 getDelegator: this.getDelegator.bind(this),
10267                                 addEvent: this.addEvent.bind(this),
10268                                 removeEvent: this.removeEvent.bind(this),
10269                                 addEvents: this.addEvents.bind(this),
10270                                 removeEvents: this.removeEvents.bind(this),
10271                                 fireEvent: this.fireEvent.bind(this),
10272                                 applyFilters: this.apply.bind(this),
10273                                 applyFilter: this.applyFilter.bind(this),
10274                                 getContentElement: this.getContentElement.bind(this),
10275                                 cleanup: this.cleanup.bind(this),
10276                                 getContainerSize: function(){
10277                                         return this.getContentElement().measure(function(){
10278                                                 return this.getSize();
10279                                         });
10280                                 }.bind(this),
10281                                 error: function(){ this.fireEvent('error', arguments); }.bind(this),
10282                                 fail: function(){
10283                                         var msg = Array.join(arguments, ' ');
10284                                         throw new Error(msg);
10285                                 },
10286                                 warn: function(){
10287                                         this.fireEvent('warn', arguments);
10288                                 }.bind(this)
10289                         });
10290                 },
10291
10292                 getDelegator: function(){
10293                         return this.delegator;
10294                 },
10295
10296                 setDelegator: function(delegator){
10297                         if (!instanceOf(delegator, Delegator)) throw new Error('Behavior.setDelegator only accepts instances of Delegator.');
10298                         this.delegator = delegator;
10299                         return this;
10300                 },
10301
10302                 getContentElement: function(){
10303                         return this.options.container || document.body;
10304                 },
10305
10306                 //Applies all the behavior filters for an element.
10307                 //container - (element) an element to apply the filters registered with this Behavior instance to.
10308                 //force - (boolean; optional) passed through to applyFilter (see it for docs)
10309                 apply: function(container, force){
10310                   this._getElements(container).each(function(element){
10311                                 var plugins = [];
10312                                 element.getBehaviors().each(function(name){
10313                                         var filter = this.getFilter(name);
10314                                         if (!filter){
10315                                                 this.fireEvent('error', ['There is no filter registered with this name: ', name, element]);
10316                                         } else {
10317                                                 var config = filter.config;
10318                                                 if (config.delay !== undefined){
10319                                                         this.applyFilter.delay(filter.config.delay, this, [element, filter, force]);
10320                                                 } else if(config.delayUntil){
10321                                                         this._delayFilterUntil(element, filter, force);
10322                                                 } else if(config.initializer){
10323                                                         this._customInit(element, filter, force);
10324                                                 } else {
10325                                                         plugins.append(this.applyFilter(element, filter, force, true));
10326                                                 }
10327                                         }
10328                                 }, this);
10329                                 plugins.each(function(plugin){ plugin(); });
10330                         }, this);
10331                         return this;
10332                 },
10333
10334                 _getElements: function(container){
10335                         if (typeOf(this.options.selector) == 'function') return this.options.selector(container);
10336                         else return document.id(container).getElements(this.options.selector);
10337                 },
10338
10339                 //delays a filter until the event specified in filter.config.delayUntil is fired on the element
10340                 _delayFilterUntil: function(element, filter, force){
10341                         var events = filter.config.delayUntil.split(','),
10342                             attached = {},
10343                             inited = false;
10344                         var clear = function(){
10345                                 events.each(function(event){
10346                                         element.removeEvent(event, attached[event]);
10347                                 });
10348                                 clear = function(){};
10349                         };
10350                         events.each(function(event){
10351                                 var init = function(e){
10352                                         clear();
10353                                         if (inited) return;
10354                                         inited = true;
10355                                         var setup = filter.setup;
10356                                         filter.setup = function(element, api, _pluginResult){
10357                                                 api.event = e;
10358                                                 return setup.apply(filter, [element, api, _pluginResult]);
10359                                         };
10360                                         this.applyFilter(element, filter, force);
10361                                         filter.setup = setup;
10362                                 }.bind(this);
10363                                 element.addEvent(event, init);
10364                                 attached[event] = init;
10365                         }, this);
10366                 },
10367
10368                 //runs custom initiliazer defined in filter.config.initializer
10369                 _customInit: function(element, filter, force){
10370                         var api = new this.API(element, filter.name);
10371                         api.runSetup = this.applyFilter.pass([element, filter, force], this);
10372                         filter.config.initializer(element, api);
10373                 },
10374
10375                 //Applies a specific behavior to a specific element.
10376                 //element - the element to which to apply the behavior
10377                 //filter - (object) a specific behavior filter, typically one registered with this instance or registered globally.
10378                 //force - (boolean; optional) apply the behavior to each element it matches, even if it was previously applied. Defaults to *false*.
10379                 //_returnPlugins - (boolean; optional; internal) if true, plugins are not rendered but instead returned as an array of functions
10380                 //_pluginTargetResult - (obj; optional internal) if this filter is a plugin for another, this is whatever that target filter returned
10381                 //                      (an instance of a class for example)
10382                 applyFilter: function(element, filter, force, _returnPlugins, _pluginTargetResult){
10383                         var pluginsToReturn = [];
10384                         if (this.options.breakOnErrors){
10385                                 pluginsToReturn = this._applyFilter.apply(this, arguments);
10386                         } else {
10387                                 try {
10388                                         pluginsToReturn = this._applyFilter.apply(this, arguments);
10389                                 } catch (e){
10390                                         this.fireEvent('error', ['Could not apply the behavior ' + filter.name, e]);
10391                                 }
10392                         }
10393                         return _returnPlugins ? pluginsToReturn : this;
10394                 },
10395
10396                 //see argument list above for applyFilter
10397                 _applyFilter: function(element, filter, force, _returnPlugins, _pluginTargetResult){
10398                         var pluginsToReturn = [];
10399                         element = document.id(element);
10400                         //get the filters already applied to this element
10401                         var applied = getApplied(element);
10402                         //if this filter is not yet applied to the element, or we are forcing the filter
10403                         if (!applied[filter.name] || force){
10404                                 //if it was previously applied, garbage collect it
10405                                 if (applied[filter.name]) applied[filter.name].cleanup(element);
10406                                 var api = new this.API(element, filter.name);
10407
10408                                 //deprecated
10409                                 api.markForCleanup = filter.markForCleanup.bind(filter);
10410                                 api.onCleanup = function(fn){
10411                                         filter.markForCleanup(element, fn);
10412                                 };
10413
10414                                 if (filter.config.deprecated && this.options.enableDeprecation) api.deprecate(filter.config.deprecated);
10415                                 if (filter.config.deprecateAsJSON && this.options.enableDeprecation) api.deprecate(filter.config.deprecatedAsJSON, true);
10416
10417                                 //deal with requirements and defaults
10418                                 if (filter.config.requireAs){
10419                                         api.requireAs(filter.config.requireAs);
10420                                 } else if (filter.config.require){
10421                                         api.require.apply(api, Array.from(filter.config.require));
10422                                 }
10423
10424                                 if (filter.config.defaults) api.setDefault(filter.config.defaults);
10425
10426                                 //apply the filter
10427                                 var result = filter.setup(element, api, _pluginTargetResult);
10428                                 if (filter.config.returns && !instanceOf(result, filter.config.returns)){
10429                                         throw new Error("Filter " + filter.name + " did not return a valid instance.");
10430                                 }
10431                                 element.store('Behavior Filter result:' + filter.name, result);
10432                                 //and mark it as having been previously applied
10433                                 applied[filter.name] = filter;
10434                                 //apply all the plugins for this filter
10435                                 var plugins = this.getPlugins(filter.name);
10436                                 if (plugins){
10437                                         for (var name in plugins){
10438                                                 if (_returnPlugins){
10439                                                         pluginsToReturn.push(this.applyFilter.pass([element, plugins[name], force, null, result], this));
10440                                                 } else {
10441                                                         this.applyFilter(element, plugins[name], force, null, result);
10442                                                 }
10443                                         }
10444                                 }
10445                         }
10446                         return pluginsToReturn;
10447                 },
10448
10449                 //given a name, returns a registered behavior
10450                 getFilter: function(name){
10451                         return this._registered[name] || Behavior.getFilter(name);
10452                 },
10453
10454                 getPlugins: function(name){
10455                         return this._plugins[name] || Behavior._plugins[name];
10456                 },
10457
10458                 //Garbage collects all applied filters for an element and its children.
10459                 //element - (*element*) container to cleanup
10460                 //ignoreChildren - (*boolean*; optional) if *true* only the element will be cleaned, otherwise the element and all the
10461                 //        children with filters applied will be cleaned. Defaults to *false*.
10462                 cleanup: function(element, ignoreChildren){
10463                         element = document.id(element);
10464                         var applied = getApplied(element);
10465                         for (var filter in applied){
10466                                 applied[filter].cleanup(element);
10467                                 element.eliminate('Behavior Filter result:' + filter);
10468                                 delete applied[filter];
10469                         }
10470                         if (!ignoreChildren) this._getElements(element).each(this.cleanup, this);
10471                         return this;
10472                 }
10473
10474         });
10475
10476         //Export these for use elsewhere (notabily: Delegator).
10477         Behavior.getLog = getLog;
10478         Behavior.PassMethods = PassMethods;
10479
10480
10481         //Returns the applied behaviors for an element.
10482         var getApplied = function(el){
10483                 return el.retrieve('_appliedBehaviors', {});
10484         };
10485
10486         //Registers a behavior filter.
10487         //name - the name of the filter
10488         //fn - a function that applies the filter to the given element
10489         //overwrite - (boolean) if true, will overwrite existing filter if one exists; defaults to false.
10490         var addFilter = function(name, fn, overwrite){
10491                 if (!this._registered[name] || overwrite) this._registered[name] = new Behavior.Filter(name, fn);
10492                 else throw new Error('Could not add the Behavior filter "' + name  +'" as a previous trigger by that same name exists.');
10493         };
10494
10495         var addFilters = function(obj, overwrite){
10496                 for (var name in obj){
10497                         addFilter.apply(this, [name, obj[name], overwrite]);
10498                 }
10499         };
10500
10501         //Registers a behavior plugin
10502         //filterName - (*string*) the filter (or plugin) this is a plugin for
10503         //name - (*string*) the name of this plugin
10504         //setup - a function that applies the filter to the given element
10505         var addPlugin = function(filterName, name, setup, overwrite){
10506                 if (!this._plugins[filterName]) this._plugins[filterName] = {};
10507                 if (!this._plugins[filterName][name] || overwrite) this._plugins[filterName][name] = new Behavior.Filter(name, setup);
10508                 else throw new Error('Could not add the Behavior filter plugin "' + name  +'" as a previous trigger by that same name exists.');
10509         };
10510
10511         var addPlugins = function(obj, overwrite){
10512                 for (var name in obj){
10513                         addPlugin.apply(this, [obj[name].fitlerName, obj[name].name, obj[name].setup], overwrite);
10514                 }
10515         };
10516
10517         var setFilterDefaults = function(name, defaults){
10518                 var filter = this.getFilter(name);
10519                 if (!filter.config.defaults) filter.config.defaults = {};
10520                 Object.append(filter.config.defaults, defaults);
10521         };
10522
10523         //Add methods to the Behavior namespace for global registration.
10524         Object.append(Behavior, {
10525                 _registered: {},
10526                 _plugins: {},
10527                 addGlobalFilter: addFilter,
10528                 addGlobalFilters: addFilters,
10529                 addGlobalPlugin: addPlugin,
10530                 addGlobalPlugins: addPlugins,
10531                 setFilterDefaults: setFilterDefaults,
10532                 getFilter: function(name){
10533                         return this._registered[name];
10534                 }
10535         });
10536         //Add methods to the Behavior class for instance registration.
10537         Behavior.implement({
10538                 _registered: {},
10539                 _plugins: {},
10540                 addFilter: addFilter,
10541                 addFilters: addFilters,
10542                 addPlugin: addPlugin,
10543                 addPlugins: addPlugins,
10544                 setFilterDefaults: setFilterDefaults
10545         });
10546
10547         //This class is an actual filter that, given an element, alters it with specific behaviors.
10548         Behavior.Filter = new Class({
10549
10550                 config: {
10551                         /**
10552                                 returns: Foo,
10553                                 require: ['req1', 'req2'],
10554                                 //or
10555                                 requireAs: {
10556                                         req1: Boolean,
10557                                         req2: Number,
10558                                         req3: String
10559                                 },
10560                                 defaults: {
10561                                         opt1: false,
10562                                         opt2: 2
10563                                 },
10564                                 //simple example:
10565                                 setup: function(element, API){
10566                                         var kids = element.getElements(API.get('selector'));
10567                                         //some validation still has to occur here
10568                                         if (!kids.length) API.fail('there were no child elements found that match ', API.get('selector'));
10569                                         if (kids.length < 2) API.warn("there weren't more than 2 kids that match", API.get('selector'));
10570                                         var fooInstance = new Foo(kids, API.get('opt1', 'opt2'));
10571                                         API.onCleanup(function(){
10572                                                 fooInstance.destroy();
10573                                         });
10574                                         return fooInstance;
10575                                 },
10576                                 delayUntil: 'mouseover',
10577                                 //OR
10578                                 delay: 100,
10579                                 //OR
10580                                 initializer: function(element, API){
10581                                         element.addEvent('mouseover', API.runSetup); //same as specifying event
10582                                         //or
10583                                         API.runSetup.delay(100); //same as specifying delay
10584                                         //or something completely esoteric
10585                                         var timer = (function(){
10586                                                 if (element.hasClass('foo')){
10587                                                         clearInterval(timer);
10588                                                         API.runSetup();
10589                                                 }
10590                                         }).periodical(100);
10591                                         //or
10592                                         API.addEvent('someBehaviorEvent', API.runSetup);
10593                                 });
10594                                 */
10595                 },
10596
10597                 //Pass in an object with the following properties:
10598                 //name - the name of this filter
10599                 //setup - a function that applies the filter to the given element
10600                 initialize: function(name, setup){
10601                         this.name = name;
10602                         if (typeOf(setup) == "function"){
10603                                 this.setup = setup;
10604                         } else {
10605                                 Object.append(this.config, setup);
10606                                 this.setup = this.config.setup;
10607                         }
10608                         this._cleanupFunctions = new Table();
10609                 },
10610
10611                 //Stores a garbage collection pointer for a specific element.
10612                 //Example: if your filter enhances all the inputs in the container
10613                 //you might have a function that removes that enhancement for garbage collection.
10614                 //You would mark each input matched with its own cleanup function.
10615                 //NOTE: this MUST be the element passed to the filter - the element with this filters
10616                 //      name in its data-behavior property. I.E.:
10617                 //<form data-behavior="FormValidator">
10618                 //  <input type="text" name="email"/>
10619                 //</form>
10620                 //If this filter is FormValidator, you can mark the form for cleanup, but not, for example
10621                 //the input. Only elements that match this filter can be marked.
10622                 markForCleanup: function(element, fn){
10623                         var functions = this._cleanupFunctions.get(element);
10624                         if (!functions) functions = [];
10625                         functions.include(fn);
10626                         this._cleanupFunctions.set(element, functions);
10627                         return this;
10628                 },
10629
10630                 //Garbage collect a specific element.
10631                 //NOTE: this should be an element that has a data-behavior property that matches this filter.
10632                 cleanup: function(element){
10633                         var marks = this._cleanupFunctions.get(element);
10634                         if (marks){
10635                                 marks.each(function(fn){ fn(); });
10636                                 this._cleanupFunctions.erase(element);
10637                         }
10638                         return this;
10639                 }
10640
10641         });
10642
10643         Behavior.elementDataProperty = 'behavior';
10644
10645         Element.implement({
10646
10647                 addBehaviorFilter: function(name){
10648                         return this.setData(Behavior.elementDataProperty, this.getBehaviors().include(name).join(' '));
10649                 },
10650
10651                 removeBehaviorFilter: function(name){
10652                         return this.setData(Behavior.elementDataProperty, this.getBehaviors().erase(name).join(' '));
10653                 },
10654
10655                 getBehaviors: function(){
10656                         var filters = this.getData(Behavior.elementDataProperty);
10657                         if (!filters) return [];
10658                         return filters.trim().split(spaceOrCommaRegex);
10659                 },
10660
10661                 hasBehavior: function(name){
10662                         return this.getBehaviors().contains(name);
10663                 },
10664
10665                 getBehaviorResult: function(name){
10666                         return this.retrieve('Behavior Filter result:' + name);
10667                 }
10668
10669         });
10670
10671
10672 })();
10673
10674
10675 // Begin: Source/Drag/Drag.js
10676 /*
10677 ---
10678
10679 script: Drag.js
10680
10681 name: Drag
10682
10683 description: The base Drag Class. Can be used to drag and resize Elements using mouse events.
10684
10685 license: MIT-style license
10686
10687 authors:
10688   - Valerio Proietti
10689   - Tom Occhinno
10690   - Jan Kassens
10691
10692 requires:
10693   - Core/Events
10694   - Core/Options
10695   - Core/Element.Event
10696   - Core/Element.Style
10697   - Core/Element.Dimensions
10698   - /MooTools.More
10699
10700 provides: [Drag]
10701 ...
10702
10703 */
10704
10705 var Drag = new Class({
10706
10707         Implements: [Events, Options],
10708
10709         options: {/*
10710                 onBeforeStart: function(thisElement){},
10711                 onStart: function(thisElement, event){},
10712                 onSnap: function(thisElement){},
10713                 onDrag: function(thisElement, event){},
10714                 onCancel: function(thisElement){},
10715                 onComplete: function(thisElement, event){},*/
10716                 snap: 6,
10717                 unit: 'px',
10718                 grid: false,
10719                 style: true,
10720                 limit: false,
10721                 handle: false,
10722                 invert: false,
10723                 preventDefault: false,
10724                 stopPropagation: false,
10725                 modifiers: {x: 'left', y: 'top'}
10726         },
10727
10728         initialize: function(){
10729                 var params = Array.link(arguments, {
10730                         'options': Type.isObject,
10731                         'element': function(obj){
10732                                 return obj != null;
10733                         }
10734                 });
10735
10736                 this.element = document.id(params.element);
10737                 this.document = this.element.getDocument();
10738                 this.setOptions(params.options || {});
10739                 var htype = typeOf(this.options.handle);
10740                 this.handles = ((htype == 'array' || htype == 'collection') ? $$(this.options.handle) : document.id(this.options.handle)) || this.element;
10741                 this.mouse = {'now': {}, 'pos': {}};
10742                 this.value = {'start': {}, 'now': {}};
10743
10744                 this.selection = (Browser.ie) ? 'selectstart' : 'mousedown';
10745
10746
10747                 if (Browser.ie && !Drag.ondragstartFixed){
10748                         document.ondragstart = Function.from(false);
10749                         Drag.ondragstartFixed = true;
10750                 }
10751
10752                 this.bound = {
10753                         start: this.start.bind(this),
10754                         check: this.check.bind(this),
10755                         drag: this.drag.bind(this),
10756                         stop: this.stop.bind(this),
10757                         cancel: this.cancel.bind(this),
10758                         eventStop: Function.from(false)
10759                 };
10760                 this.attach();
10761         },
10762
10763         attach: function(){
10764                 this.handles.addEvent('mousedown', this.bound.start);
10765                 return this;
10766         },
10767
10768         detach: function(){
10769                 this.handles.removeEvent('mousedown', this.bound.start);
10770                 return this;
10771         },
10772
10773         start: function(event){
10774                 var options = this.options;
10775
10776                 if (event.rightClick) return;
10777
10778                 if (options.preventDefault) event.preventDefault();
10779                 if (options.stopPropagation) event.stopPropagation();
10780                 this.mouse.start = event.page;
10781
10782                 this.fireEvent('beforeStart', this.element);
10783
10784                 var limit = options.limit;
10785                 this.limit = {x: [], y: []};
10786
10787                 var z, coordinates;
10788                 for (z in options.modifiers){
10789                         if (!options.modifiers[z]) continue;
10790
10791                         var style = this.element.getStyle(options.modifiers[z]);
10792
10793                         // Some browsers (IE and Opera) don't always return pixels.
10794                         if (style && !style.match(/px$/)){
10795                                 if (!coordinates) coordinates = this.element.getCoordinates(this.element.getOffsetParent());
10796                                 style = coordinates[options.modifiers[z]];
10797                         }
10798
10799                         if (options.style) this.value.now[z] = (style || 0).toInt();
10800                         else this.value.now[z] = this.element[options.modifiers[z]];
10801
10802                         if (options.invert) this.value.now[z] *= -1;
10803
10804                         this.mouse.pos[z] = event.page[z] - this.value.now[z];
10805
10806                         if (limit && limit[z]){
10807                                 var i = 2;
10808                                 while (i--){
10809                                         var limitZI = limit[z][i];
10810                                         if (limitZI || limitZI === 0) this.limit[z][i] = (typeof limitZI == 'function') ? limitZI() : limitZI;
10811                                 }
10812                         }
10813                 }
10814
10815                 if (typeOf(this.options.grid) == 'number') this.options.grid = {
10816                         x: this.options.grid,
10817                         y: this.options.grid
10818                 };
10819
10820                 var events = {
10821                         mousemove: this.bound.check,
10822                         mouseup: this.bound.cancel
10823                 };
10824                 events[this.selection] = this.bound.eventStop;
10825                 this.document.addEvents(events);
10826         },
10827
10828         check: function(event){
10829                 if (this.options.preventDefault) event.preventDefault();
10830                 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)));
10831                 if (distance > this.options.snap){
10832                         this.cancel();
10833                         this.document.addEvents({
10834                                 mousemove: this.bound.drag,
10835                                 mouseup: this.bound.stop
10836                         });
10837                         this.fireEvent('start', [this.element, event]).fireEvent('snap', this.element);
10838                 }
10839         },
10840
10841         drag: function(event){
10842                 var options = this.options;
10843
10844                 if (options.preventDefault) event.preventDefault();
10845                 this.mouse.now = event.page;
10846
10847                 for (var z in options.modifiers){
10848                         if (!options.modifiers[z]) continue;
10849                         this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z];
10850
10851                         if (options.invert) this.value.now[z] *= -1;
10852
10853                         if (options.limit && this.limit[z]){
10854                                 if ((this.limit[z][1] || this.limit[z][1] === 0) && (this.value.now[z] > this.limit[z][1])){
10855                                         this.value.now[z] = this.limit[z][1];
10856                                 } else if ((this.limit[z][0] || this.limit[z][0] === 0) && (this.value.now[z] < this.limit[z][0])){
10857                                         this.value.now[z] = this.limit[z][0];
10858                                 }
10859                         }
10860
10861                         if (options.grid[z]) this.value.now[z] -= ((this.value.now[z] - (this.limit[z][0]||0)) % options.grid[z]);
10862
10863                         if (options.style) this.element.setStyle(options.modifiers[z], this.value.now[z] + options.unit);
10864                         else this.element[options.modifiers[z]] = this.value.now[z];
10865                 }
10866
10867                 this.fireEvent('drag', [this.element, event]);
10868         },
10869
10870         cancel: function(event){
10871                 this.document.removeEvents({
10872                         mousemove: this.bound.check,
10873                         mouseup: this.bound.cancel
10874                 });
10875                 if (event){
10876                         this.document.removeEvent(this.selection, this.bound.eventStop);
10877                         this.fireEvent('cancel', this.element);
10878                 }
10879         },
10880
10881         stop: function(event){
10882                 var events = {
10883                         mousemove: this.bound.drag,
10884                         mouseup: this.bound.stop
10885                 };
10886                 events[this.selection] = this.bound.eventStop;
10887                 this.document.removeEvents(events);
10888                 if (event) this.fireEvent('complete', [this.element, event]);
10889         }
10890
10891 });
10892
10893 Element.implement({
10894
10895         makeResizable: function(options){
10896                 var drag = new Drag(this, Object.merge({
10897                         modifiers: {
10898                                 x: 'width',
10899                                 y: 'height'
10900                         }
10901                 }, options));
10902
10903                 this.store('resizer', drag);
10904                 return drag.addEvent('drag', function(){
10905                         this.fireEvent('resize', drag);
10906                 }.bind(this));
10907         }
10908
10909 });
10910
10911
10912 // Begin: Source/Drag/Drag.Move.js
10913 /*
10914 ---
10915
10916 script: Drag.Move.js
10917
10918 name: Drag.Move
10919
10920 description: A Drag extension that provides support for the constraining of draggables to containers and droppables.
10921
10922 license: MIT-style license
10923
10924 authors:
10925   - Valerio Proietti
10926   - Tom Occhinno
10927   - Jan Kassens
10928   - Aaron Newton
10929   - Scott Kyle
10930
10931 requires:
10932   - Core/Element.Dimensions
10933   - /Drag
10934
10935 provides: [Drag.Move]
10936
10937 ...
10938 */
10939
10940 Drag.Move = new Class({
10941
10942         Extends: Drag,
10943
10944         options: {/*
10945                 onEnter: function(thisElement, overed){},
10946                 onLeave: function(thisElement, overed){},
10947                 onDrop: function(thisElement, overed, event){},*/
10948                 droppables: [],
10949                 container: false,
10950                 precalculate: false,
10951                 includeMargins: true,
10952                 checkDroppables: true
10953         },
10954
10955         initialize: function(element, options){
10956                 this.parent(element, options);
10957                 element = this.element;
10958
10959                 this.droppables = $$(this.options.droppables);
10960                 this.container = document.id(this.options.container);
10961
10962                 if (this.container && typeOf(this.container) != 'element')
10963                         this.container = document.id(this.container.getDocument().body);
10964
10965                 if (this.options.style){
10966                         if (this.options.modifiers.x == 'left' && this.options.modifiers.y == 'top'){
10967                                 var parent = element.getOffsetParent(),
10968                                         styles = element.getStyles('left', 'top');
10969                                 if (parent && (styles.left == 'auto' || styles.top == 'auto')){
10970                                         element.setPosition(element.getPosition(parent));
10971                                 }
10972                         }
10973
10974                         if (element.getStyle('position') == 'static') element.setStyle('position', 'absolute');
10975                 }
10976
10977                 this.addEvent('start', this.checkDroppables, true);
10978                 this.overed = null;
10979         },
10980
10981         start: function(event){
10982                 if (this.container) this.options.limit = this.calculateLimit();
10983
10984                 if (this.options.precalculate){
10985                         this.positions = this.droppables.map(function(el){
10986                                 return el.getCoordinates();
10987                         });
10988                 }
10989
10990                 this.parent(event);
10991         },
10992
10993         calculateLimit: function(){
10994                 var element = this.element,
10995                         container = this.container,
10996
10997                         offsetParent = document.id(element.getOffsetParent()) || document.body,
10998                         containerCoordinates = container.getCoordinates(offsetParent),
10999                         elementMargin = {},
11000                         elementBorder = {},
11001                         containerMargin = {},
11002                         containerBorder = {},
11003                         offsetParentPadding = {};
11004
11005                 ['top', 'right', 'bottom', 'left'].each(function(pad){
11006                         elementMargin[pad] = element.getStyle('margin-' + pad).toInt();
11007                         elementBorder[pad] = element.getStyle('border-' + pad).toInt();
11008                         containerMargin[pad] = container.getStyle('margin-' + pad).toInt();
11009                         containerBorder[pad] = container.getStyle('border-' + pad).toInt();
11010                         offsetParentPadding[pad] = offsetParent.getStyle('padding-' + pad).toInt();
11011                 }, this);
11012
11013                 var width = element.offsetWidth + elementMargin.left + elementMargin.right,
11014                         height = element.offsetHeight + elementMargin.top + elementMargin.bottom,
11015                         left = 0,
11016                         top = 0,
11017                         right = containerCoordinates.right - containerBorder.right - width,
11018                         bottom = containerCoordinates.bottom - containerBorder.bottom - height;
11019
11020                 if (this.options.includeMargins){
11021                         left += elementMargin.left;
11022                         top += elementMargin.top;
11023                 } else {
11024                         right += elementMargin.right;
11025                         bottom += elementMargin.bottom;
11026                 }
11027
11028                 if (element.getStyle('position') == 'relative'){
11029                         var coords = element.getCoordinates(offsetParent);
11030                         coords.left -= element.getStyle('left').toInt();
11031                         coords.top -= element.getStyle('top').toInt();
11032
11033                         left -= coords.left;
11034                         top -= coords.top;
11035                         if (container.getStyle('position') != 'relative'){
11036                                 left += containerBorder.left;
11037                                 top += containerBorder.top;
11038                         }
11039                         right += elementMargin.left - coords.left;
11040                         bottom += elementMargin.top - coords.top;
11041
11042                         if (container != offsetParent){
11043                                 left += containerMargin.left + offsetParentPadding.left;
11044                                 top += ((Browser.ie6 || Browser.ie7) ? 0 : containerMargin.top) + offsetParentPadding.top;
11045                         }
11046                 } else {
11047                         left -= elementMargin.left;
11048                         top -= elementMargin.top;
11049                         if (container != offsetParent){
11050                                 left += containerCoordinates.left + containerBorder.left;
11051                                 top += containerCoordinates.top + containerBorder.top;
11052                         }
11053                 }
11054
11055                 return {
11056                         x: [left, right],
11057                         y: [top, bottom]
11058                 };
11059         },
11060
11061         getDroppableCoordinates: function(element){
11062                 var position = element.getCoordinates();
11063                 if (element.getStyle('position') == 'fixed'){
11064                         var scroll = window.getScroll();
11065                         position.left += scroll.x;
11066                         position.right += scroll.x;
11067                         position.top += scroll.y;
11068                         position.bottom += scroll.y;
11069                 }
11070                 return position;
11071         },
11072
11073         checkDroppables: function(){
11074                 var overed = this.droppables.filter(function(el, i){
11075                         el = this.positions ? this.positions[i] : this.getDroppableCoordinates(el);
11076                         var now = this.mouse.now;
11077                         return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top);
11078                 }, this).getLast();
11079
11080                 if (this.overed != overed){
11081                         if (this.overed) this.fireEvent('leave', [this.element, this.overed]);
11082                         if (overed) this.fireEvent('enter', [this.element, overed]);
11083                         this.overed = overed;
11084                 }
11085         },
11086
11087         drag: function(event){
11088                 this.parent(event);
11089                 if (this.options.checkDroppables && this.droppables.length) this.checkDroppables();
11090         },
11091
11092         stop: function(event){
11093                 this.checkDroppables();
11094                 this.fireEvent('drop', [this.element, this.overed, event]);
11095                 this.overed = null;
11096                 return this.parent(event);
11097         }
11098
11099 });
11100
11101 Element.implement({
11102
11103         makeDraggable: function(options){
11104                 var drag = new Drag.Move(this, options);
11105                 this.store('dragger', drag);
11106                 return drag;
11107         }
11108
11109 });
11110
11111
11112 // Begin: Source/UI/StickyWin.Drag.js
11113 /*
11114 ---
11115
11116 name: StickyWin.Drag
11117
11118 description: Implements drag and resize functionaity into StickyWin.Fx. See StickyWin.Fx for the options.
11119
11120 license: MIT-Style License
11121
11122 requires: [More/Class.Refactor, More/Drag.Move, StickyWin]
11123
11124 provides: StickyWin.Drag
11125
11126 ...
11127 */
11128 StickyWin = Class.refactor(StickyWin, {
11129         options: {
11130                 draggable: false,
11131                 dragOptions: {
11132                         onComplete: function(){}
11133                 },
11134                 dragHandleSelector: '.dragHandle',
11135                 resizable: false,
11136                 resizeOptions: {
11137                         onComplete: function(){}
11138                 },
11139                 resizeHandleSelector: ''
11140         },
11141         setContent: function(){
11142                 this.previous.apply(this, arguments);
11143                 if (this.options.draggable) this.makeDraggable();
11144                 if (this.options.resizable) this.makeResizable();
11145                 return this;
11146         },
11147         makeDraggable: function(){
11148                 var toggled = this.toggleVisible(true);
11149                 if (this.options.useIframeShim) {
11150                         this.makeIframeShim();
11151                         var onComplete = (this.options.dragOptions.onComplete);
11152                         this.options.dragOptions.onComplete = function(){
11153                                 onComplete();
11154                                 this.shim.position();
11155                         }.bind(this);
11156                 }
11157                 if (this.options.dragHandleSelector) {
11158                         var handle = this.win.getElement(this.options.dragHandleSelector);
11159                         if (handle) {
11160                                 handle.setStyle('cursor','move');
11161                                 this.options.dragOptions.handle = handle;
11162                         }
11163                 }
11164                 this.win.makeDraggable(this.options.dragOptions);
11165                 if (toggled) this.toggleVisible(false);
11166         },
11167         makeResizable: function(){
11168                 var toggled = this.toggleVisible(true);
11169                 if (this.options.useIframeShim) {
11170                         this.makeIframeShim();
11171                         var onComplete = (this.options.resizeOptions.onComplete);
11172                         this.options.resizeOptions.onComplete = function(){
11173                                 onComplete();
11174                                 this.shim.position();
11175                         }.bind(this);
11176                 }
11177                 if (this.options.resizeHandleSelector) {
11178                         var handle = this.win.getElement(this.options.resizeHandleSelector);
11179                         if (handle) this.options.resizeOptions.handle = this.win.getElement(this.options.resizeHandleSelector);
11180                 }
11181                 this.win.makeResizable(this.options.resizeOptions);
11182                 if (toggled) this.toggleVisible(false);
11183         },
11184         toggleVisible: function(show){
11185                 if (!this.visible && show == null || show) {
11186                         this.win.setStyles({
11187                                 display: 'block',
11188                                 opacity: 0
11189                         });
11190                         return true;
11191                 } else if (show != null && !show){
11192                         this.win.setStyles({
11193                                 display: 'none',
11194                                 opacity: 1
11195                         });
11196                         return false;
11197                 }
11198                 return false;
11199         }
11200 });
11201 StickyWin.Fx = StickyWin;
11202
11203 // Begin: Source/Behaviors/Behavior.StickyWin.js
11204 /*
11205 ---
11206 name: Behavior.StickyWin
11207 description: Behaviors for StickyWin instances.
11208 provides: [Behavior.StickyWin]
11209 requires: [Behavior/Behavior, /StickyWin, /StickyWin.Modal, /StickyWin.Fx, /StickyWin.Drag, More/Array.Extras, More/Object.Extras]
11210 script: Behavior.Tabs.js
11211
11212 ...
11213 */
11214
11215 Behavior.addGlobalFilters({
11216
11217         'StickyWin.Modal': {
11218                 defaults: {
11219                         destroyOnClose: true,
11220                         closeOnClickOut: true,
11221                         closeOnEsc: true,
11222                         draggable: false,
11223                         resizable: false
11224                 },
11225                 returns: StickyWin.Modal,
11226                 setup: function(element, api) {
11227                         var flex = element.getElement('.flex'),
11228                             height = api.getAs(Number, 'height') || (window.getSize().y * .9);
11229
11230                         if (flex){
11231                                 element.measure(function(){
11232                                         var tmp = new Element('span', { styles: { display: 'none' }}).replaces(flex),
11233                                             remainder = element.getSize().y;
11234                                         var padding = ['padding-top', 'padding-bottom', 'margin-top', 'margin-bottom', 'border-top-width', 'border-bottom-width'].map(function(style){
11235                                                 return flex.getStyle(style).toInt();
11236                                         }).sum();
11237                                         flex.setStyle('max-height', height - remainder - padding);
11238                                         flex.replaces(tmp);
11239                                 });
11240                         }
11241
11242                         var options = Object.merge({
11243                                         content: element
11244                                 },
11245                                 Object.cleanValues(
11246                                         api.getAs({
11247                                                 closeClassName: String,
11248                                                 pinClassName: String,
11249                                                 className: String,
11250                                                 edge: String,
11251                                                 position: String,
11252                                                 offset: Object,
11253                                                 relativeTo: String,
11254                                                 width: Number,
11255                                                 height: Number,
11256                                                 timeout: Number,
11257                                                 destroyOnClose: Boolean,
11258                                                 closeOnClickOut: Boolean,
11259                                                 closeOnEsc: Boolean,
11260                                                 //modal options
11261                                                 maskOptions: Object,
11262                                                 //draggable options
11263                                                 draggable: Boolean,
11264                                                 dragHandleSelector: String,
11265                                                 resizable: Boolean,
11266                                                 resizeHandleSelector: String
11267                                         })
11268                                 )
11269                         );
11270
11271                         if (options.mask) options.closeOnClickOut = false;
11272
11273                         var sw = new StickyWin.Modal(options);
11274                         api.onCleanup(function(){
11275                                 if (!sw.destroyed) sw.destroy();
11276                         });
11277                         sw.addEvent('destroy', function(){
11278                                 api.cleanup(element);
11279                         });
11280                         return sw;
11281                 }
11282         }
11283
11284 });
11285
11286
11287 // Begin: Source/Utilities/Color.js
11288 /*
11289 ---
11290
11291 script: Color.js
11292
11293 name: Color
11294
11295 description: Class for creating and manipulating colors in JavaScript. Supports HSB -> RGB Conversions and vice versa.
11296
11297 license: MIT-style license
11298
11299 authors:
11300   - Valerio Proietti
11301
11302 requires:
11303   - Core/Array
11304   - Core/String
11305   - Core/Number
11306   - Core/Hash
11307   - Core/Function
11308   - MooTools.More
11309
11310 provides: [Color]
11311
11312 ...
11313 */
11314
11315 (function(){
11316
11317 var Color = this.Color = new Type('Color', function(color, type){
11318         if (arguments.length >= 3){
11319                 type = 'rgb'; color = Array.slice(arguments, 0, 3);
11320         } else if (typeof color == 'string'){
11321                 if (color.match(/rgb/)) color = color.rgbToHex().hexToRgb(true);
11322                 else if (color.match(/hsb/)) color = color.hsbToRgb();
11323                 else color = color.hexToRgb(true);
11324         }
11325         type = type || 'rgb';
11326         switch (type){
11327                 case 'hsb':
11328                         var old = color;
11329                         color = color.hsbToRgb();
11330                         color.hsb = old;
11331                 break;
11332                 case 'hex': color = color.hexToRgb(true); break;
11333         }
11334         color.rgb = color.slice(0, 3);
11335         color.hsb = color.hsb || color.rgbToHsb();
11336         color.hex = color.rgbToHex();
11337         return Object.append(color, this);
11338 });
11339
11340 Color.implement({
11341
11342         mix: function(){
11343                 var colors = Array.slice(arguments);
11344                 var alpha = (typeOf(colors.getLast()) == 'number') ? colors.pop() : 50;
11345                 var rgb = this.slice();
11346                 colors.each(function(color){
11347                         color = new Color(color);
11348                         for (var i = 0; i < 3; i++) rgb[i] = Math.round((rgb[i] / 100 * (100 - alpha)) + (color[i] / 100 * alpha));
11349                 });
11350                 return new Color(rgb, 'rgb');
11351         },
11352
11353         invert: function(){
11354                 return new Color(this.map(function(value){
11355                         return 255 - value;
11356                 }));
11357         },
11358
11359         setHue: function(value){
11360                 return new Color([value, this.hsb[1], this.hsb[2]], 'hsb');
11361         },
11362
11363         setSaturation: function(percent){
11364                 return new Color([this.hsb[0], percent, this.hsb[2]], 'hsb');
11365         },
11366
11367         setBrightness: function(percent){
11368                 return new Color([this.hsb[0], this.hsb[1], percent], 'hsb');
11369         }
11370
11371 });
11372
11373 this.$RGB = function(r, g, b){
11374         return new Color([r, g, b], 'rgb');
11375 };
11376
11377 this.$HSB = function(h, s, b){
11378         return new Color([h, s, b], 'hsb');
11379 };
11380
11381 this.$HEX = function(hex){
11382         return new Color(hex, 'hex');
11383 };
11384
11385 Array.implement({
11386
11387         rgbToHsb: function(){
11388                 var red = this[0],
11389                                 green = this[1],
11390                                 blue = this[2],
11391                                 hue = 0;
11392                 var max = Math.max(red, green, blue),
11393                                 min = Math.min(red, green, blue);
11394                 var delta = max - min;
11395                 var brightness = max / 255,
11396                                 saturation = (max != 0) ? delta / max : 0;
11397                 if (saturation != 0){
11398                         var rr = (max - red) / delta;
11399                         var gr = (max - green) / delta;
11400                         var br = (max - blue) / delta;
11401                         if (red == max) hue = br - gr;
11402                         else if (green == max) hue = 2 + rr - br;
11403                         else hue = 4 + gr - rr;
11404                         hue /= 6;
11405                         if (hue < 0) hue++;
11406                 }
11407                 return [Math.round(hue * 360), Math.round(saturation * 100), Math.round(brightness * 100)];
11408         },
11409
11410         hsbToRgb: function(){
11411                 var br = Math.round(this[2] / 100 * 255);
11412                 if (this[1] == 0){
11413                         return [br, br, br];
11414                 } else {
11415                         var hue = this[0] % 360;
11416                         var f = hue % 60;
11417                         var p = Math.round((this[2] * (100 - this[1])) / 10000 * 255);
11418                         var q = Math.round((this[2] * (6000 - this[1] * f)) / 600000 * 255);
11419                         var t = Math.round((this[2] * (6000 - this[1] * (60 - f))) / 600000 * 255);
11420                         switch (Math.floor(hue / 60)){
11421                                 case 0: return [br, t, p];
11422                                 case 1: return [q, br, p];
11423                                 case 2: return [p, br, t];
11424                                 case 3: return [p, q, br];
11425                                 case 4: return [t, p, br];
11426                                 case 5: return [br, p, q];
11427                         }
11428                 }
11429                 return false;
11430         }
11431
11432 });
11433
11434 String.implement({
11435
11436         rgbToHsb: function(){
11437                 var rgb = this.match(/\d{1,3}/g);
11438                 return (rgb) ? rgb.rgbToHsb() : null;
11439         },
11440
11441         hsbToRgb: function(){
11442                 var hsb = this.match(/\d{1,3}/g);
11443                 return (hsb) ? hsb.hsbToRgb() : null;
11444         }
11445
11446 });
11447
11448 })();
11449
11450
11451
11452 // Begin: Source/Class/Events.Pseudos.js
11453 /*
11454 ---
11455
11456 name: Events.Pseudos
11457
11458 description: Adds the functionality to add pseudo events
11459
11460 license: MIT-style license
11461
11462 authors:
11463   - Arian Stolwijk
11464
11465 requires: [Core/Class.Extras, Core/Slick.Parser, More/MooTools.More]
11466
11467 provides: [Events.Pseudos]
11468
11469 ...
11470 */
11471
11472 (function(){
11473
11474 Events.Pseudos = function(pseudos, addEvent, removeEvent){
11475
11476         var storeKey = '_monitorEvents:';
11477
11478         var storageOf = function(object){
11479                 return {
11480                         store: object.store ? function(key, value){
11481                                 object.store(storeKey + key, value);
11482                         } : function(key, value){
11483                                 (object._monitorEvents || (object._monitorEvents = {}))[key] = value;
11484                         },
11485                         retrieve: object.retrieve ? function(key, dflt){
11486                                 return object.retrieve(storeKey + key, dflt);
11487                         } : function(key, dflt){
11488                                 if (!object._monitorEvents) return dflt;
11489                                 return object._monitorEvents[key] || dflt;
11490                         }
11491                 };
11492         };
11493
11494         var splitType = function(type){
11495                 if (type.indexOf(':') == -1 || !pseudos) return null;
11496
11497                 var parsed = Slick.parse(type).expressions[0][0],
11498                         parsedPseudos = parsed.pseudos,
11499                         l = parsedPseudos.length,
11500                         splits = [];
11501
11502                 while (l--){
11503                         var pseudo = parsedPseudos[l].key,
11504                                 listener = pseudos[pseudo];
11505                         if (listener != null) splits.push({
11506                                 event: parsed.tag,
11507                                 value: parsedPseudos[l].value,
11508                                 pseudo: pseudo,
11509                                 original: type,
11510                                 listener: listener
11511                         });
11512                 }
11513                 return splits.length ? splits : null;
11514         };
11515
11516         return {
11517
11518                 addEvent: function(type, fn, internal){
11519                         var split = splitType(type);
11520                         if (!split) return addEvent.call(this, type, fn, internal);
11521
11522                         var storage = storageOf(this),
11523                                 events = storage.retrieve(type, []),
11524                                 eventType = split[0].event,
11525                                 args = Array.slice(arguments, 2),
11526                                 stack = fn,
11527                                 self = this;
11528
11529                         split.each(function(item){
11530                                 var listener = item.listener,
11531                                         stackFn = stack;
11532                                 if (listener == false) eventType += ':' + item.pseudo + '(' + item.value + ')';
11533                                 else stack = function(){
11534                                         listener.call(self, item, stackFn, arguments, stack);
11535                                 };
11536                         });
11537
11538                         events.include({type: eventType, event: fn, monitor: stack});
11539                         storage.store(type, events);
11540
11541                         if (type != eventType) addEvent.apply(this, [type, fn].concat(args));
11542                         return addEvent.apply(this, [eventType, stack].concat(args));
11543                 },
11544
11545                 removeEvent: function(type, fn){
11546                         var split = splitType(type);
11547                         if (!split) return removeEvent.call(this, type, fn);
11548
11549                         var storage = storageOf(this),
11550                                 events = storage.retrieve(type);
11551                         if (!events) return this;
11552
11553                         var args = Array.slice(arguments, 2);
11554
11555                         removeEvent.apply(this, [type, fn].concat(args));
11556                         events.each(function(monitor, i){
11557                                 if (!fn || monitor.event == fn) removeEvent.apply(this, [monitor.type, monitor.monitor].concat(args));
11558                                 delete events[i];
11559                         }, this);
11560
11561                         storage.store(type, events);
11562                         return this;
11563                 }
11564
11565         };
11566
11567 };
11568
11569 var pseudos = {
11570
11571         once: function(split, fn, args, monitor){
11572                 fn.apply(this, args);
11573                 this.removeEvent(split.event, monitor)
11574                         .removeEvent(split.original, fn);
11575         },
11576
11577         throttle: function(split, fn, args){
11578                 if (!fn._throttled){
11579                         fn.apply(this, args);
11580                         fn._throttled = setTimeout(function(){
11581                                 fn._throttled = false;
11582                         }, split.value || 250);
11583                 }
11584         },
11585
11586         pause: function(split, fn, args){
11587                 clearTimeout(fn._pause);
11588                 fn._pause = fn.delay(split.value || 250, this, args);
11589         }
11590
11591 };
11592
11593 Events.definePseudo = function(key, listener){
11594         pseudos[key] = listener;
11595         return this;
11596 };
11597
11598 Events.lookupPseudo = function(key){
11599         return pseudos[key];
11600 };
11601
11602 var proto = Events.prototype;
11603 Events.implement(Events.Pseudos(pseudos, proto.addEvent, proto.removeEvent));
11604
11605 ['Request', 'Fx'].each(function(klass){
11606         if (this[klass]) this[klass].implement(Events.prototype);
11607 });
11608
11609 })();
11610
11611
11612 // Begin: Source/Element/Element.Event.Pseudos.js
11613 /*
11614 ---
11615
11616 name: Element.Event.Pseudos
11617
11618 description: Adds the functionality to add pseudo events for Elements
11619
11620 license: MIT-style license
11621
11622 authors:
11623   - Arian Stolwijk
11624
11625 requires: [Core/Element.Event, Core/Element.Delegation, Events.Pseudos]
11626
11627 provides: [Element.Event.Pseudos, Element.Delegation]
11628
11629 ...
11630 */
11631
11632 (function(){
11633
11634 var pseudos = {relay: false},
11635         copyFromEvents = ['once', 'throttle', 'pause'],
11636         count = copyFromEvents.length;
11637
11638 while (count--) pseudos[copyFromEvents[count]] = Events.lookupPseudo(copyFromEvents[count]);
11639
11640 DOMEvent.definePseudo = function(key, listener){
11641         pseudos[key] = listener;
11642         return this;
11643 };
11644
11645 var proto = Element.prototype;
11646 [Element, Window, Document].invoke('implement', Events.Pseudos(pseudos, proto.addEvent, proto.removeEvent));
11647
11648 })();
11649
11650
11651 // Begin: Source/Element/Element.Event.Pseudos.Keys.js
11652 /*
11653 ---
11654
11655 name: Element.Event.Pseudos.Keys
11656
11657 description: Adds functionality fire events if certain keycombinations are pressed
11658
11659 license: MIT-style license
11660
11661 authors:
11662   - Arian Stolwijk
11663
11664 requires: [Element.Event.Pseudos]
11665
11666 provides: [Element.Event.Pseudos.Keys]
11667
11668 ...
11669 */
11670
11671 (function(){
11672
11673 var keysStoreKey = '$moo:keys-pressed',
11674         keysKeyupStoreKey = '$moo:keys-keyup';
11675
11676
11677 DOMEvent.definePseudo('keys', function(split, fn, args){
11678
11679         var event = args[0],
11680                 keys = [],
11681                 pressed = this.retrieve(keysStoreKey, []);
11682
11683         keys.append(split.value.replace('++', function(){
11684                 keys.push('+'); // shift++ and shift+++a
11685                 return '';
11686         }).split('+'));
11687
11688         pressed.include(event.key);
11689
11690         if (keys.every(function(key){
11691                 return pressed.contains(key);
11692         })) fn.apply(this, args);
11693
11694         this.store(keysStoreKey, pressed);
11695
11696         if (!this.retrieve(keysKeyupStoreKey)){
11697                 var keyup = function(event){
11698                         (function(){
11699                                 pressed = this.retrieve(keysStoreKey, []).erase(event.key);
11700                                 this.store(keysStoreKey, pressed);
11701                         }).delay(0, this); // Fix for IE
11702                 };
11703                 this.store(keysKeyupStoreKey, keyup).addEvent('keyup', keyup);
11704         }
11705
11706 });
11707
11708 DOMEvent.defineKeys({
11709         '16': 'shift',
11710         '17': 'control',
11711         '18': 'alt',
11712         '20': 'capslock',
11713         '33': 'pageup',
11714         '34': 'pagedown',
11715         '35': 'end',
11716         '36': 'home',
11717         '144': 'numlock',
11718         '145': 'scrolllock',
11719         '186': ';',
11720         '187': '=',
11721         '188': ',',
11722         '190': '.',
11723         '191': '/',
11724         '192': '`',
11725         '219': '[',
11726         '220': '\\',
11727         '221': ']',
11728         '222': "'",
11729         '107': '+'
11730 }).defineKey(Browser.firefox ? 109 : 189, '-');
11731
11732 })();
11733
11734
11735 // Begin: Source/Interface/Keyboard.js
11736 /*
11737 ---
11738
11739 script: Keyboard.js
11740
11741 name: Keyboard
11742
11743 description: 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.
11744
11745 license: MIT-style license
11746
11747 authors:
11748   - Perrin Westrich
11749   - Aaron Newton
11750   - Scott Kyle
11751
11752 requires:
11753   - Core/Events
11754   - Core/Options
11755   - Core/Element.Event
11756   - Element.Event.Pseudos.Keys
11757
11758 provides: [Keyboard]
11759
11760 ...
11761 */
11762
11763 (function(){
11764
11765         var Keyboard = this.Keyboard = new Class({
11766
11767                 Extends: Events,
11768
11769                 Implements: [Options],
11770
11771                 options: {/*
11772                         onActivate: function(){},
11773                         onDeactivate: function(){},*/
11774                         defaultEventType: 'keydown',
11775                         active: false,
11776                         manager: null,
11777                         events: {},
11778                         nonParsedEvents: ['activate', 'deactivate', 'onactivate', 'ondeactivate', 'changed', 'onchanged']
11779                 },
11780
11781                 initialize: function(options){
11782                         if (options && options.manager){
11783                                 this._manager = options.manager;
11784                                 delete options.manager;
11785                         }
11786                         this.setOptions(options);
11787                         this._setup();
11788                 },
11789
11790                 addEvent: function(type, fn, internal){
11791                         return this.parent(Keyboard.parse(type, this.options.defaultEventType, this.options.nonParsedEvents), fn, internal);
11792                 },
11793
11794                 removeEvent: function(type, fn){
11795                         return this.parent(Keyboard.parse(type, this.options.defaultEventType, this.options.nonParsedEvents), fn);
11796                 },
11797
11798                 toggleActive: function(){
11799                         return this[this.isActive() ? 'deactivate' : 'activate']();
11800                 },
11801
11802                 activate: function(instance){
11803                         if (instance){
11804                                 if (instance.isActive()) return this;
11805                                 //if we're stealing focus, store the last keyboard to have it so the relinquish command works
11806                                 if (this._activeKB && instance != this._activeKB){
11807                                         this.previous = this._activeKB;
11808                                         this.previous.fireEvent('deactivate');
11809                                 }
11810                                 //if we're enabling a child, assign it so that events are now passed to it
11811                                 this._activeKB = instance.fireEvent('activate');
11812                                 Keyboard.manager.fireEvent('changed');
11813                         } else if (this._manager){
11814                                 //else we're enabling ourselves, we must ask our parent to do it for us
11815                                 this._manager.activate(this);
11816                         }
11817                         return this;
11818                 },
11819
11820                 isActive: function(){
11821                         return this._manager ? (this._manager._activeKB == this) : (Keyboard.manager == this);
11822                 },
11823
11824                 deactivate: function(instance){
11825                         if (instance){
11826                                 if (instance === this._activeKB){
11827                                         this._activeKB = null;
11828                                         instance.fireEvent('deactivate');
11829                                         Keyboard.manager.fireEvent('changed');
11830                                 }
11831                         } else if (this._manager){
11832                                 this._manager.deactivate(this);
11833                         }
11834                         return this;
11835                 },
11836
11837                 relinquish: function(){
11838                         if (this.isActive() && this._manager && this._manager.previous) this._manager.activate(this._manager.previous);
11839                         else this.deactivate();
11840                         return this;
11841                 },
11842
11843                 //management logic
11844                 manage: function(instance){
11845                         if (instance._manager) instance._manager.drop(instance);
11846                         this._instances.push(instance);
11847                         instance._manager = this;
11848                         if (!this._activeKB) this.activate(instance);
11849                         return this;
11850                 },
11851
11852                 drop: function(instance){
11853                         instance.relinquish();
11854                         this._instances.erase(instance);
11855                         if (this._activeKB == instance){
11856                                 if (this.previous && this._instances.contains(this.previous)) this.activate(this.previous);
11857                                 else this._activeKB = this._instances[0];
11858                         }
11859                         return this;
11860                 },
11861
11862                 trace: function(){
11863                         Keyboard.trace(this);
11864                 },
11865
11866                 each: function(fn){
11867                         Keyboard.each(this, fn);
11868                 },
11869
11870                 /*
11871                         PRIVATE METHODS
11872                 */
11873
11874                 _instances: [],
11875
11876                 _disable: function(instance){
11877                         if (this._activeKB == instance) this._activeKB = null;
11878                 },
11879
11880                 _setup: function(){
11881                         this.addEvents(this.options.events);
11882                         //if this is the root manager, nothing manages it
11883                         if (Keyboard.manager && !this._manager) Keyboard.manager.manage(this);
11884                         if (this.options.active) this.activate();
11885                         else this.relinquish();
11886                 },
11887
11888                 _handle: function(event, type){
11889                         //Keyboard.stop(event) prevents key propagation
11890                         if (event.preventKeyboardPropagation) return;
11891
11892                         var bubbles = !!this._manager;
11893                         if (bubbles && this._activeKB){
11894                                 this._activeKB._handle(event, type);
11895                                 if (event.preventKeyboardPropagation) return;
11896                         }
11897                         this.fireEvent(type, event);
11898
11899                         if (!bubbles && this._activeKB) this._activeKB._handle(event, type);
11900                 }
11901
11902         });
11903
11904         var parsed = {};
11905         var modifiers = ['shift', 'control', 'alt', 'meta'];
11906         var regex = /^(?:shift|control|ctrl|alt|meta)$/;
11907
11908         Keyboard.parse = function(type, eventType, ignore){
11909                 if (ignore && ignore.contains(type.toLowerCase())) return type;
11910
11911                 type = type.toLowerCase().replace(/^(keyup|keydown):/, function($0, $1){
11912                         eventType = $1;
11913                         return '';
11914                 });
11915
11916                 if (!parsed[type]){
11917                         var key, mods = {};
11918                         type.split('+').each(function(part){
11919                                 if (regex.test(part)) mods[part] = true;
11920                                 else key = part;
11921                         });
11922
11923                         mods.control = mods.control || mods.ctrl; // allow both control and ctrl
11924
11925                         var keys = [];
11926                         modifiers.each(function(mod){
11927                                 if (mods[mod]) keys.push(mod);
11928                         });
11929
11930                         if (key) keys.push(key);
11931                         parsed[type] = keys.join('+');
11932                 }
11933
11934                 return eventType + ':keys(' + parsed[type] + ')';
11935         };
11936
11937         Keyboard.each = function(keyboard, fn){
11938                 var current = keyboard || Keyboard.manager;
11939                 while (current){
11940                         fn.run(current);
11941                         current = current._activeKB;
11942                 }
11943         };
11944
11945         Keyboard.stop = function(event){
11946                 event.preventKeyboardPropagation = true;
11947         };
11948
11949         Keyboard.manager = new Keyboard({
11950                 active: true
11951         });
11952
11953         Keyboard.trace = function(keyboard){
11954                 keyboard = keyboard || Keyboard.manager;
11955                 var hasConsole = window.console && console.log;
11956                 if (hasConsole) console.log('the following items have focus: ');
11957                 Keyboard.each(keyboard, function(current){
11958                         if (hasConsole) console.log(document.id(current.widget) || current.wiget || current);
11959                 });
11960         };
11961
11962         var handler = function(event){
11963                 var keys = [];
11964                 modifiers.each(function(mod){
11965                         if (event[mod]) keys.push(mod);
11966                 });
11967
11968                 if (!regex.test(event.key)) keys.push(event.key);
11969                 Keyboard.manager._handle(event, event.type + ':keys(' + keys.join('+') + ')');
11970         };
11971
11972         document.addEvents({
11973                 'keyup': handler,
11974                 'keydown': handler
11975         });
11976
11977 })();
11978
11979
11980 // Begin: Source/Interface/Keyboard.Extras.js
11981 /*
11982 ---
11983
11984 script: Keyboard.Extras.js
11985
11986 name: Keyboard.Extras
11987
11988 description: 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.
11989
11990 license: MIT-style license
11991
11992 authors:
11993   - Perrin Westrich
11994
11995 requires:
11996   - /Keyboard
11997   - /MooTools.More
11998
11999 provides: [Keyboard.Extras]
12000
12001 ...
12002 */
12003 Keyboard.prototype.options.nonParsedEvents.combine(['rebound', 'onrebound']);
12004
12005 Keyboard.implement({
12006
12007         /*
12008                 shortcut should be in the format of:
12009                 {
12010                         'keys': 'shift+s', // the default to add as an event.
12011                         'description': 'blah blah blah', // a brief description of the functionality.
12012                         'handler': function(){} // the event handler to run when keys are pressed.
12013                 }
12014         */
12015         addShortcut: function(name, shortcut){
12016                 this._shortcuts = this._shortcuts || [];
12017                 this._shortcutIndex = this._shortcutIndex || {};
12018
12019                 shortcut.getKeyboard = Function.from(this);
12020                 shortcut.name = name;
12021                 this._shortcutIndex[name] = shortcut;
12022                 this._shortcuts.push(shortcut);
12023                 if (shortcut.keys) this.addEvent(shortcut.keys, shortcut.handler);
12024                 return this;
12025         },
12026
12027         addShortcuts: function(obj){
12028                 for (var name in obj) this.addShortcut(name, obj[name]);
12029                 return this;
12030         },
12031
12032         removeShortcut: function(name){
12033                 var shortcut = this.getShortcut(name);
12034                 if (shortcut && shortcut.keys){
12035                         this.removeEvent(shortcut.keys, shortcut.handler);
12036                         delete this._shortcutIndex[name];
12037                         this._shortcuts.erase(shortcut);
12038                 }
12039                 return this;
12040         },
12041
12042         removeShortcuts: function(names){
12043                 names.each(this.removeShortcut, this);
12044                 return this;
12045         },
12046
12047         getShortcuts: function(){
12048                 return this._shortcuts || [];
12049         },
12050
12051         getShortcut: function(name){
12052                 return (this._shortcutIndex || {})[name];
12053         }
12054
12055 });
12056
12057 Keyboard.rebind = function(newKeys, shortcuts){
12058         Array.from(shortcuts).each(function(shortcut){
12059                 shortcut.getKeyboard().removeEvent(shortcut.keys, shortcut.handler);
12060                 shortcut.getKeyboard().addEvent(newKeys, shortcut.handler);
12061                 shortcut.keys = newKeys;
12062                 shortcut.getKeyboard().fireEvent('rebound');
12063         });
12064 };
12065
12066
12067 Keyboard.getActiveShortcuts = function(keyboard){
12068         var activeKBS = [], activeSCS = [];
12069         Keyboard.each(keyboard, [].push.bind(activeKBS));
12070         activeKBS.each(function(kb){ activeSCS.extend(kb.getShortcuts()); });
12071         return activeSCS;
12072 };
12073
12074 Keyboard.getShortcut = function(name, keyboard, opts){
12075         opts = opts || {};
12076         var shortcuts = opts.many ? [] : null,
12077                 set = opts.many ? function(kb){
12078                                 var shortcut = kb.getShortcut(name);
12079                                 if (shortcut) shortcuts.push(shortcut);
12080                         } : function(kb){
12081                                 if (!shortcuts) shortcuts = kb.getShortcut(name);
12082                         };
12083         Keyboard.each(keyboard, set);
12084         return shortcuts;
12085 };
12086
12087 Keyboard.getShortcuts = function(name, keyboard){
12088         return Keyboard.getShortcut(name, keyboard, { many: true });
12089 };
12090
12091
12092 // Begin: Source/Locale/Locale.js
12093 /*
12094 ---
12095
12096 script: Locale.js
12097
12098 name: Locale
12099
12100 description: Provides methods for localization.
12101
12102 license: MIT-style license
12103
12104 authors:
12105   - Aaron Newton
12106   - Arian Stolwijk
12107
12108 requires:
12109   - Core/Events
12110   - /Object.Extras
12111   - /MooTools.More
12112
12113 provides: [Locale, Lang]
12114
12115 ...
12116 */
12117
12118 (function(){
12119
12120 var current = null,
12121         locales = {},
12122         inherits = {};
12123
12124 var getSet = function(set){
12125         if (instanceOf(set, Locale.Set)) return set;
12126         else return locales[set];
12127 };
12128
12129 var Locale = this.Locale = {
12130
12131         define: function(locale, set, key, value){
12132                 var name;
12133                 if (instanceOf(locale, Locale.Set)){
12134                         name = locale.name;
12135                         if (name) locales[name] = locale;
12136                 } else {
12137                         name = locale;
12138                         if (!locales[name]) locales[name] = new Locale.Set(name);
12139                         locale = locales[name];
12140                 }
12141
12142                 if (set) locale.define(set, key, value);
12143
12144                 /*<1.2compat>*/
12145                 if (set == 'cascade') return Locale.inherit(name, key);
12146                 /*</1.2compat>*/
12147
12148                 if (!current) current = locale;
12149
12150                 return locale;
12151         },
12152
12153         use: function(locale){
12154                 locale = getSet(locale);
12155
12156                 if (locale){
12157                         current = locale;
12158
12159                         this.fireEvent('change', locale);
12160
12161                         /*<1.2compat>*/
12162                         this.fireEvent('langChange', locale.name);
12163                         /*</1.2compat>*/
12164                 }
12165
12166                 return this;
12167         },
12168
12169         getCurrent: function(){
12170                 return current;
12171         },
12172
12173         get: function(key, args){
12174                 return (current) ? current.get(key, args) : '';
12175         },
12176
12177         inherit: function(locale, inherits, set){
12178                 locale = getSet(locale);
12179
12180                 if (locale) locale.inherit(inherits, set);
12181                 return this;
12182         },
12183
12184         list: function(){
12185                 return Object.keys(locales);
12186         }
12187
12188 };
12189
12190 Object.append(Locale, new Events);
12191
12192 Locale.Set = new Class({
12193
12194         sets: {},
12195
12196         inherits: {
12197                 locales: [],
12198                 sets: {}
12199         },
12200
12201         initialize: function(name){
12202                 this.name = name || '';
12203         },
12204
12205         define: function(set, key, value){
12206                 var defineData = this.sets[set];
12207                 if (!defineData) defineData = {};
12208
12209                 if (key){
12210                         if (typeOf(key) == 'object') defineData = Object.merge(defineData, key);
12211                         else defineData[key] = value;
12212                 }
12213                 this.sets[set] = defineData;
12214
12215                 return this;
12216         },
12217
12218         get: function(key, args, _base){
12219                 var value = Object.getFromPath(this.sets, key);
12220                 if (value != null){
12221                         var type = typeOf(value);
12222                         if (type == 'function') value = value.apply(null, Array.from(args));
12223                         else if (type == 'object') value = Object.clone(value);
12224                         return value;
12225                 }
12226
12227                 // get value of inherited locales
12228                 var index = key.indexOf('.'),
12229                         set = index < 0 ? key : key.substr(0, index),
12230                         names = (this.inherits.sets[set] || []).combine(this.inherits.locales).include('en-US');
12231                 if (!_base) _base = [];
12232
12233                 for (var i = 0, l = names.length; i < l; i++){
12234                         if (_base.contains(names[i])) continue;
12235                         _base.include(names[i]);
12236
12237                         var locale = locales[names[i]];
12238                         if (!locale) continue;
12239
12240                         value = locale.get(key, args, _base);
12241                         if (value != null) return value;
12242                 }
12243
12244                 return '';
12245         },
12246
12247         inherit: function(names, set){
12248                 names = Array.from(names);
12249
12250                 if (set && !this.inherits.sets[set]) this.inherits.sets[set] = [];
12251
12252                 var l = names.length;
12253                 while (l--) (set ? this.inherits.sets[set] : this.inherits.locales).unshift(names[l]);
12254
12255                 return this;
12256         }
12257
12258 });
12259
12260 /*<1.2compat>*/
12261 var lang = MooTools.lang = {};
12262
12263 Object.append(lang, Locale, {
12264         setLanguage: Locale.use,
12265         getCurrentLanguage: function(){
12266                 var current = Locale.getCurrent();
12267                 return (current) ? current.name : null;
12268         },
12269         set: function(){
12270                 Locale.define.apply(this, arguments);
12271                 return this;
12272         },
12273         get: function(set, key, args){
12274                 if (key) set += '.' + key;
12275                 return Locale.get(set, args);
12276         }
12277 });
12278 /*</1.2compat>*/
12279
12280 })();
12281
12282
12283 // Begin: Source/Locale/Locale.en-US.Number.js
12284 /*
12285 ---
12286
12287 name: Locale.en-US.Number
12288
12289 description: Number messages for US English.
12290
12291 license: MIT-style license
12292
12293 authors:
12294   - Arian Stolwijk
12295
12296 requires:
12297   - /Locale
12298
12299 provides: [Locale.en-US.Number]
12300
12301 ...
12302 */
12303
12304 Locale.define('en-US', 'Number', {
12305
12306         decimal: '.',
12307         group: ',',
12308
12309 /*      Commented properties are the defaults for Number.format
12310         decimals: 0,
12311         precision: 0,
12312         scientific: null,
12313
12314         prefix: null,
12315         suffic: null,
12316
12317         // Negative/Currency/percentage will mixin Number
12318         negative: {
12319                 prefix: '-'
12320         },*/
12321
12322         currency: {
12323 //              decimals: 2,
12324                 prefix: '$ '
12325         }/*,
12326
12327         percentage: {
12328                 decimals: 2,
12329                 suffix: '%'
12330         }*/
12331
12332 });
12333
12334
12335
12336
12337 // Begin: Source/Types/Number.Format.js
12338 /*
12339 ---
12340 name: Number.Format
12341 description: Extends the Number Type object to include a number formatting method.
12342 license: MIT-style license
12343 authors: [Arian Stolwijk]
12344 requires: [Core/Number, Locale.en-US.Number]
12345 # Number.Extras is for compatibility
12346 provides: [Number.Format, Number.Extras]
12347 ...
12348 */
12349
12350
12351 Number.implement({
12352
12353         format: function(options){
12354                 // Thanks dojo and YUI for some inspiration
12355                 var value = this;
12356                 options = options ? Object.clone(options) : {};
12357                 var getOption = function(key){
12358                         if (options[key] != null) return options[key];
12359                         return Locale.get('Number.' + key);
12360                 };
12361
12362                 var negative = value < 0,
12363                         decimal = getOption('decimal'),
12364                         precision = getOption('precision'),
12365                         group = getOption('group'),
12366                         decimals = getOption('decimals');
12367
12368                 if (negative){
12369                         var negativeLocale = getOption('negative') || {};
12370                         if (negativeLocale.prefix == null && negativeLocale.suffix == null) negativeLocale.prefix = '-';
12371                         ['prefix', 'suffix'].each(function(key){
12372                                 if (negativeLocale[key]) options[key] = getOption(key) + negativeLocale[key];
12373                         });
12374
12375                         value = -value;
12376                 }
12377
12378                 var prefix = getOption('prefix'),
12379                         suffix = getOption('suffix');
12380
12381                 if (decimals !== '' && decimals >= 0 && decimals <= 20) value = value.toFixed(decimals);
12382                 if (precision >= 1 && precision <= 21) value = (+value).toPrecision(precision);
12383
12384                 value += '';
12385                 var index;
12386                 if (getOption('scientific') === false && value.indexOf('e') > -1){
12387                         var match = value.split('e'),
12388                                 zeros = +match[1];
12389                         value = match[0].replace('.', '');
12390
12391                         if (zeros < 0){
12392                                 zeros = -zeros - 1;
12393                                 index = match[0].indexOf('.');
12394                                 if (index > -1) zeros -= index - 1;
12395                                 while (zeros--) value = '0' + value;
12396                                 value = '0.' + value;
12397                         } else {
12398                                 index = match[0].lastIndexOf('.');
12399                                 if (index > -1) zeros -= match[0].length - index - 1;
12400                                 while (zeros--) value += '0';
12401                         }
12402                 }
12403
12404                 if (decimal != '.') value = value.replace('.', decimal);
12405
12406                 if (group){
12407                         index = value.lastIndexOf(decimal);
12408                         index = (index > -1) ? index : value.length;
12409                         var newOutput = value.substring(index),
12410                                 i = index;
12411
12412                         while (i--){
12413                                 if ((index - i - 1) % 3 == 0 && i != (index - 1)) newOutput = group + newOutput;
12414                                 newOutput = value.charAt(i) + newOutput;
12415                         }
12416
12417                         value = newOutput;
12418                 }
12419
12420                 if (prefix) value = prefix + value;
12421                 if (suffix) value += suffix;
12422
12423                 return value;
12424         },
12425
12426         formatCurrency: function(decimals){
12427                 var locale = Locale.get('Number.currency') || {};
12428                 if (locale.scientific == null) locale.scientific = false;
12429                 locale.decimals = decimals != null ? decimals
12430                         : (locale.decimals == null ? 2 : locale.decimals);
12431
12432                 return this.format(locale);
12433         },
12434
12435         formatPercentage: function(decimals){
12436                 var locale = Locale.get('Number.percentage') || {};
12437                 if (locale.suffix == null) locale.suffix = '%';
12438                 locale.decimals = decimals != null ? decimals
12439                         : (locale.decimals == null ? 2 : locale.decimals);
12440
12441                 return this.format(locale);
12442         }
12443
12444 });
12445
12446
12447 // Begin: Source/Request/Request.Periodical.js
12448 /*
12449 ---
12450
12451 script: Request.Periodical.js
12452
12453 name: Request.Periodical
12454
12455 description: Requests the same URL to pull data from a server but increases the intervals if no data is returned to reduce the load
12456
12457 license: MIT-style license
12458
12459 authors:
12460   - Christoph Pojer
12461
12462 requires:
12463   - Core/Request
12464   - /MooTools.More
12465
12466 provides: [Request.Periodical]
12467
12468 ...
12469 */
12470
12471 Request.implement({
12472
12473         options: {
12474                 initialDelay: 5000,
12475                 delay: 5000,
12476                 limit: 60000
12477         },
12478
12479         startTimer: function(data){
12480                 var fn = function(){
12481                         if (!this.running) this.send({data: data});
12482                 };
12483                 this.lastDelay = this.options.initialDelay;
12484                 this.timer = fn.delay(this.lastDelay, this);
12485                 this.completeCheck = function(response){
12486                         clearTimeout(this.timer);
12487                         this.lastDelay = (response) ? this.options.delay : (this.lastDelay + this.options.delay).min(this.options.limit);
12488                         this.timer = fn.delay(this.lastDelay, this);
12489                 };
12490                 return this.addEvent('complete', this.completeCheck);
12491         },
12492
12493         stopTimer: function(){
12494                 clearTimeout(this.timer);
12495                 return this.removeEvent('complete', this.completeCheck);
12496         }
12497
12498 });
12499
12500
12501 // Begin: Source/Request/Request.JSONP.js
12502 /*
12503 ---
12504
12505 script: Request.JSONP.js
12506
12507 name: Request.JSONP
12508
12509 description: Defines Request.JSONP, a class for cross domain javascript via script injection.
12510
12511 license: MIT-style license
12512
12513 authors:
12514   - Aaron Newton
12515   - Guillermo Rauch
12516   - Arian Stolwijk
12517
12518 requires:
12519   - Core/Element
12520   - Core/Request
12521   - MooTools.More
12522
12523 provides: [Request.JSONP]
12524
12525 ...
12526 */
12527
12528 Request.JSONP = new Class({
12529
12530         Implements: [Chain, Events, Options],
12531
12532         options: {/*
12533                 onRequest: function(src, scriptElement){},
12534                 onComplete: function(data){},
12535                 onSuccess: function(data){},
12536                 onCancel: function(){},
12537                 onTimeout: function(){},
12538                 onError: function(){}, */
12539                 onRequest: function(src){
12540                         if (this.options.log && window.console && console.log){
12541                                 console.log('JSONP retrieving script with url:' + src);
12542                         }
12543                 },
12544                 onError: function(src){
12545                         if (this.options.log && window.console && console.warn){
12546                                 console.warn('JSONP '+ src +' will fail in Internet Explorer, which enforces a 2083 bytes length limit on URIs');
12547                         }
12548                 },
12549                 url: '',
12550                 callbackKey: 'callback',
12551                 injectScript: document.head,
12552                 data: '',
12553                 link: 'ignore',
12554                 timeout: 0,
12555                 log: false
12556         },
12557
12558         initialize: function(options){
12559                 this.setOptions(options);
12560         },
12561
12562         send: function(options){
12563                 if (!Request.prototype.check.call(this, options)) return this;
12564                 this.running = true;
12565
12566                 var type = typeOf(options);
12567                 if (type == 'string' || type == 'element') options = {data: options};
12568                 options = Object.merge(this.options, options || {});
12569
12570                 var data = options.data;
12571                 switch (typeOf(data)){
12572                         case 'element': data = document.id(data).toQueryString(); break;
12573                         case 'object': case 'hash': data = Object.toQueryString(data);
12574                 }
12575
12576                 var index = this.index = Request.JSONP.counter++;
12577
12578                 var src = options.url +
12579                         (options.url.test('\\?') ? '&' :'?') +
12580                         (options.callbackKey) +
12581                         '=Request.JSONP.request_map.request_'+ index +
12582                         (data ? '&' + data : '');
12583
12584                 if (src.length > 2083) this.fireEvent('error', src);
12585
12586                 Request.JSONP.request_map['request_' + index] = function(){
12587                         this.success(arguments, index);
12588                 }.bind(this);
12589
12590                 var script = this.getScript(src).inject(options.injectScript);
12591                 this.fireEvent('request', [src, script]);
12592
12593                 if (options.timeout) this.timeout.delay(options.timeout, this);
12594
12595                 return this;
12596         },
12597
12598         getScript: function(src){
12599                 if (!this.script) this.script = new Element('script', {
12600                         type: 'text/javascript',
12601                         async: true,
12602                         src: src
12603                 });
12604                 return this.script;
12605         },
12606
12607         success: function(args, index){
12608                 if (!this.running) return;
12609                 this.clear()
12610                         .fireEvent('complete', args).fireEvent('success', args)
12611                         .callChain();
12612         },
12613
12614         cancel: function(){
12615                 if (this.running) this.clear().fireEvent('cancel');
12616                 return this;
12617         },
12618
12619         isRunning: function(){
12620                 return !!this.running;
12621         },
12622
12623         clear: function(){
12624                 this.running = false;
12625                 if (this.script){
12626                         this.script.destroy();
12627                         this.script = null;
12628                 }
12629                 return this;
12630         },
12631
12632         timeout: function(){
12633                 if (this.running){
12634                         this.running = false;
12635                         this.fireEvent('timeout', [this.script.get('src'), this.script]).fireEvent('failure').cancel();
12636                 }
12637                 return this;
12638         }
12639
12640 });
12641
12642 Request.JSONP.counter = 0;
12643 Request.JSONP.request_map = {};
12644
12645
12646 // Begin: Source/Types/String.QueryString.js
12647 /*
12648 ---
12649
12650 script: String.QueryString.js
12651
12652 name: String.QueryString
12653
12654 description: Methods for dealing with URI query strings.
12655
12656 license: MIT-style license
12657
12658 authors:
12659   - Sebastian Markbåge
12660   - Aaron Newton
12661   - Lennart Pilon
12662   - Valerio Proietti
12663
12664 requires:
12665   - Core/Array
12666   - Core/String
12667   - /MooTools.More
12668
12669 provides: [String.QueryString]
12670
12671 ...
12672 */
12673
12674 String.implement({
12675
12676         parseQueryString: function(decodeKeys, decodeValues){
12677                 if (decodeKeys == null) decodeKeys = true;
12678                 if (decodeValues == null) decodeValues = true;
12679
12680                 var vars = this.split(/[&;]/),
12681                         object = {};
12682                 if (!vars.length) return object;
12683
12684                 vars.each(function(val){
12685                         var index = val.indexOf('=') + 1,
12686                                 value = index ? val.substr(index) : '',
12687                                 keys = index ? val.substr(0, index - 1).match(/([^\]\[]+|(\B)(?=\]))/g) : [val],
12688                                 obj = object;
12689                         if (!keys) return;
12690                         if (decodeValues) value = decodeURIComponent(value);
12691                         keys.each(function(key, i){
12692                                 if (decodeKeys) key = decodeURIComponent(key);
12693                                 var current = obj[key];
12694
12695                                 if (i < keys.length - 1) obj = obj[key] = current || {};
12696                                 else if (typeOf(current) == 'array') current.push(value);
12697                                 else obj[key] = current != null ? [current, value] : value;
12698                         });
12699                 });
12700
12701                 return object;
12702         },
12703
12704         cleanQueryString: function(method){
12705                 return this.split('&').filter(function(val){
12706                         var index = val.indexOf('='),
12707                                 key = index < 0 ? '' : val.substr(0, index),
12708                                 value = val.substr(index + 1);
12709
12710                         return method ? method.call(null, key, value) : (value || value === 0);
12711                 }).join('&');
12712         }
12713
12714 });
12715
12716
12717 // Begin: Source/Types/URI.js
12718 /*
12719 ---
12720
12721 script: URI.js
12722
12723 name: URI
12724
12725 description: Provides methods useful in managing the window location and uris.
12726
12727 license: MIT-style license
12728
12729 authors:
12730   - Sebastian Markbåge
12731   - Aaron Newton
12732
12733 requires:
12734   - Core/Object
12735   - Core/Class
12736   - Core/Class.Extras
12737   - Core/Element
12738   - /String.QueryString
12739
12740 provides: [URI]
12741
12742 ...
12743 */
12744
12745 (function(){
12746
12747 var toString = function(){
12748         return this.get('value');
12749 };
12750
12751 var URI = this.URI = new Class({
12752
12753         Implements: Options,
12754
12755         options: {
12756                 /*base: false*/
12757         },
12758
12759         regex: /^(?:(\w+):)?(?:\/\/(?:(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)?(\.\.?$|(?:[^?#\/]*\/)*)([^?#]*)(?:\?([^#]*))?(?:#(.*))?/,
12760         parts: ['scheme', 'user', 'password', 'host', 'port', 'directory', 'file', 'query', 'fragment'],
12761         schemes: {http: 80, https: 443, ftp: 21, rtsp: 554, mms: 1755, file: 0},
12762
12763         initialize: function(uri, options){
12764                 this.setOptions(options);
12765                 var base = this.options.base || URI.base;
12766                 if (!uri) uri = base;
12767
12768                 if (uri && uri.parsed) this.parsed = Object.clone(uri.parsed);
12769                 else this.set('value', uri.href || uri.toString(), base ? new URI(base) : false);
12770         },
12771
12772         parse: function(value, base){
12773                 var bits = value.match(this.regex);
12774                 if (!bits) return false;
12775                 bits.shift();
12776                 return this.merge(bits.associate(this.parts), base);
12777         },
12778
12779         merge: function(bits, base){
12780                 if ((!bits || !bits.scheme) && (!base || !base.scheme)) return false;
12781                 if (base){
12782                         this.parts.every(function(part){
12783                                 if (bits[part]) return false;
12784                                 bits[part] = base[part] || '';
12785                                 return true;
12786                         });
12787                 }
12788                 bits.port = bits.port || this.schemes[bits.scheme.toLowerCase()];
12789                 bits.directory = bits.directory ? this.parseDirectory(bits.directory, base ? base.directory : '') : '/';
12790                 return bits;
12791         },
12792
12793         parseDirectory: function(directory, baseDirectory){
12794                 directory = (directory.substr(0, 1) == '/' ? '' : (baseDirectory || '/')) + directory;
12795                 if (!directory.test(URI.regs.directoryDot)) return directory;
12796                 var result = [];
12797                 directory.replace(URI.regs.endSlash, '').split('/').each(function(dir){
12798                         if (dir == '..' && result.length > 0) result.pop();
12799                         else if (dir != '.') result.push(dir);
12800                 });
12801                 return result.join('/') + '/';
12802         },
12803
12804         combine: function(bits){
12805                 return bits.value || bits.scheme + '://' +
12806                         (bits.user ? bits.user + (bits.password ? ':' + bits.password : '') + '@' : '') +
12807                         (bits.host || '') + (bits.port && bits.port != this.schemes[bits.scheme] ? ':' + bits.port : '') +
12808                         (bits.directory || '/') + (bits.file || '') +
12809                         (bits.query ? '?' + bits.query : '') +
12810                         (bits.fragment ? '#' + bits.fragment : '');
12811         },
12812
12813         set: function(part, value, base){
12814                 if (part == 'value'){
12815                         var scheme = value.match(URI.regs.scheme);
12816                         if (scheme) scheme = scheme[1];
12817                         if (scheme && this.schemes[scheme.toLowerCase()] == null) this.parsed = { scheme: scheme, value: value };
12818                         else this.parsed = this.parse(value, (base || this).parsed) || (scheme ? { scheme: scheme, value: value } : { value: value });
12819                 } else if (part == 'data'){
12820                         this.setData(value);
12821                 } else {
12822                         this.parsed[part] = value;
12823                 }
12824                 return this;
12825         },
12826
12827         get: function(part, base){
12828                 switch (part){
12829                         case 'value': return this.combine(this.parsed, base ? base.parsed : false);
12830                         case 'data' : return this.getData();
12831                 }
12832                 return this.parsed[part] || '';
12833         },
12834
12835         go: function(){
12836                 document.location.href = this.toString();
12837         },
12838
12839         toURI: function(){
12840                 return this;
12841         },
12842
12843         getData: function(key, part){
12844                 var qs = this.get(part || 'query');
12845                 if (!(qs || qs === 0)) return key ? null : {};
12846                 var obj = qs.parseQueryString();
12847                 return key ? obj[key] : obj;
12848         },
12849
12850         setData: function(values, merge, part){
12851                 if (typeof values == 'string'){
12852                         var data = this.getData();
12853                         data[arguments[0]] = arguments[1];
12854                         values = data;
12855                 } else if (merge){
12856                         values = Object.merge(this.getData(), values);
12857                 }
12858                 return this.set(part || 'query', Object.toQueryString(values));
12859         },
12860
12861         clearData: function(part){
12862                 return this.set(part || 'query', '');
12863         },
12864
12865         toString: toString,
12866         valueOf: toString
12867
12868 });
12869
12870 URI.regs = {
12871         endSlash: /\/$/,
12872         scheme: /^(\w+):/,
12873         directoryDot: /\.\/|\.$/
12874 };
12875
12876 URI.base = new URI(Array.from(document.getElements('base[href]', true)).getLast(), {base: document.location});
12877
12878 String.implement({
12879
12880         toURI: function(options){
12881                 return new URI(this, options);
12882         }
12883
12884 });
12885
12886 })();
12887
12888
12889 // Begin: Source/Types/URI.Relative.js
12890 /*
12891 ---
12892
12893 script: URI.Relative.js
12894
12895 name: URI.Relative
12896
12897 description: Extends the URI class to add methods for computing relative and absolute urls.
12898
12899 license: MIT-style license
12900
12901 authors:
12902   - Sebastian Markbåge
12903
12904
12905 requires:
12906   - /Class.refactor
12907   - /URI
12908
12909 provides: [URI.Relative]
12910
12911 ...
12912 */
12913
12914 URI = Class.refactor(URI, {
12915
12916         combine: function(bits, base){
12917                 if (!base || bits.scheme != base.scheme || bits.host != base.host || bits.port != base.port)
12918                         return this.previous.apply(this, arguments);
12919                 var end = bits.file + (bits.query ? '?' + bits.query : '') + (bits.fragment ? '#' + bits.fragment : '');
12920
12921                 if (!base.directory) return (bits.directory || (bits.file ? '' : './')) + end;
12922
12923                 var baseDir = base.directory.split('/'),
12924                         relDir = bits.directory.split('/'),
12925                         path = '',
12926                         offset;
12927
12928                 var i = 0;
12929                 for (offset = 0; offset < baseDir.length && offset < relDir.length && baseDir[offset] == relDir[offset]; offset++);
12930                 for (i = 0; i < baseDir.length - offset - 1; i++) path += '../';
12931                 for (i = offset; i < relDir.length - 1; i++) path += relDir[i] + '/';
12932
12933                 return (path || (bits.file ? '' : './')) + end;
12934         },
12935
12936         toAbsolute: function(base){
12937                 base = new URI(base);
12938                 if (base) base.set('directory', '').set('file', '');
12939                 return this.toRelative(base);
12940         },
12941
12942         toRelative: function(base){
12943                 return this.get('value', new URI(base));
12944         }
12945
12946 });
12947
12948
12949 // Begin: Source/Utilities/Cookie.js
12950 /*
12951 ---
12952
12953 name: Cookie
12954
12955 description: Class for creating, reading, and deleting browser Cookies.
12956
12957 license: MIT-style license.
12958
12959 credits:
12960   - Based on the functions by Peter-Paul Koch (http://quirksmode.org).
12961
12962 requires: [Options, Browser]
12963
12964 provides: Cookie
12965
12966 ...
12967 */
12968
12969 var Cookie = new Class({
12970
12971         Implements: Options,
12972
12973         options: {
12974                 path: '/',
12975                 domain: false,
12976                 duration: false,
12977                 secure: false,
12978                 document: document,
12979                 encode: true
12980         },
12981
12982         initialize: function(key, options){
12983                 this.key = key;
12984                 this.setOptions(options);
12985         },
12986
12987         write: function(value){
12988                 if (this.options.encode) value = encodeURIComponent(value);
12989                 if (this.options.domain) value += '; domain=' + this.options.domain;
12990                 if (this.options.path) value += '; path=' + this.options.path;
12991                 if (this.options.duration){
12992                         var date = new Date();
12993                         date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000);
12994                         value += '; expires=' + date.toGMTString();
12995                 }
12996                 if (this.options.secure) value += '; secure';
12997                 this.options.document.cookie = this.key + '=' + value;
12998                 return this;
12999         },
13000
13001         read: function(){
13002                 var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)');
13003                 return (value) ? decodeURIComponent(value[1]) : null;
13004         },
13005
13006         dispose: function(){
13007                 new Cookie(this.key, Object.merge({}, this.options, {duration: -1})).write('');
13008                 return this;
13009         }
13010
13011 });
13012
13013 Cookie.write = function(key, value, options){
13014         return new Cookie(key, options).write(value);
13015 };
13016
13017 Cookie.read = function(key){
13018         return new Cookie(key).read();
13019 };
13020
13021 Cookie.dispose = function(key, options){
13022         return new Cookie(key, options).dispose();
13023 };
13024
13025
13026 // Begin: Source/Locale/Locale.en-US.Date.js
13027 /*
13028 ---
13029
13030 name: Locale.en-US.Date
13031
13032 description: Date messages for US English.
13033
13034 license: MIT-style license
13035
13036 authors:
13037   - Aaron Newton
13038
13039 requires:
13040   - /Locale
13041
13042 provides: [Locale.en-US.Date]
13043
13044 ...
13045 */
13046
13047 Locale.define('en-US', 'Date', {
13048
13049         months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
13050         months_abbr: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
13051         days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
13052         days_abbr: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
13053
13054         // Culture's date order: MM/DD/YYYY
13055         dateOrder: ['month', 'date', 'year'],
13056         shortDate: '%m/%d/%Y',
13057         shortTime: '%I:%M%p',
13058         AM: 'AM',
13059         PM: 'PM',
13060         firstDayOfWeek: 0,
13061
13062         // Date.Extras
13063         ordinal: function(dayOfMonth){
13064                 // 1st, 2nd, 3rd, etc.
13065                 return (dayOfMonth > 3 && dayOfMonth < 21) ? 'th' : ['th', 'st', 'nd', 'rd', 'th'][Math.min(dayOfMonth % 10, 4)];
13066         },
13067
13068         lessThanMinuteAgo: 'less than a minute ago',
13069         minuteAgo: 'about a minute ago',
13070         minutesAgo: '{delta} minutes ago',
13071         hourAgo: 'about an hour ago',
13072         hoursAgo: 'about {delta} hours ago',
13073         dayAgo: '1 day ago',
13074         daysAgo: '{delta} days ago',
13075         weekAgo: '1 week ago',
13076         weeksAgo: '{delta} weeks ago',
13077         monthAgo: '1 month ago',
13078         monthsAgo: '{delta} months ago',
13079         yearAgo: '1 year ago',
13080         yearsAgo: '{delta} years ago',
13081
13082         lessThanMinuteUntil: 'less than a minute from now',
13083         minuteUntil: 'about a minute from now',
13084         minutesUntil: '{delta} minutes from now',
13085         hourUntil: 'about an hour from now',
13086         hoursUntil: 'about {delta} hours from now',
13087         dayUntil: '1 day from now',
13088         daysUntil: '{delta} days from now',
13089         weekUntil: '1 week from now',
13090         weeksUntil: '{delta} weeks from now',
13091         monthUntil: '1 month from now',
13092         monthsUntil: '{delta} months from now',
13093         yearUntil: '1 year from now',
13094         yearsUntil: '{delta} years from now'
13095
13096 });
13097
13098
13099 // Begin: Source/Types/Date.js
13100 /*
13101 ---
13102
13103 script: Date.js
13104
13105 name: Date
13106
13107 description: Extends the Date native object to include methods useful in managing dates.
13108
13109 license: MIT-style license
13110
13111 authors:
13112   - Aaron Newton
13113   - Nicholas Barthelemy - https://svn.nbarthelemy.com/date-js/
13114   - Harald Kirshner - mail [at] digitarald.de; http://digitarald.de
13115   - Scott Kyle - scott [at] appden.com; http://appden.com
13116
13117 requires:
13118   - Core/Array
13119   - Core/String
13120   - Core/Number
13121   - MooTools.More
13122   - Locale
13123   - Locale.en-US.Date
13124
13125 provides: [Date]
13126
13127 ...
13128 */
13129
13130 (function(){
13131
13132 var Date = this.Date;
13133
13134 var DateMethods = Date.Methods = {
13135         ms: 'Milliseconds',
13136         year: 'FullYear',
13137         min: 'Minutes',
13138         mo: 'Month',
13139         sec: 'Seconds',
13140         hr: 'Hours'
13141 };
13142
13143 ['Date', 'Day', 'FullYear', 'Hours', 'Milliseconds', 'Minutes', 'Month', 'Seconds', 'Time', 'TimezoneOffset',
13144         'Week', 'Timezone', 'GMTOffset', 'DayOfYear', 'LastMonth', 'LastDayOfMonth', 'UTCDate', 'UTCDay', 'UTCFullYear',
13145         'AMPM', 'Ordinal', 'UTCHours', 'UTCMilliseconds', 'UTCMinutes', 'UTCMonth', 'UTCSeconds', 'UTCMilliseconds'].each(function(method){
13146         Date.Methods[method.toLowerCase()] = method;
13147 });
13148
13149 var pad = function(n, digits, string){
13150         if (digits == 1) return n;
13151         return n < Math.pow(10, digits - 1) ? (string || '0') + pad(n, digits - 1, string) : n;
13152 };
13153
13154 Date.implement({
13155
13156         set: function(prop, value){
13157                 prop = prop.toLowerCase();
13158                 var method = DateMethods[prop] && 'set' + DateMethods[prop];
13159                 if (method && this[method]) this[method](value);
13160                 return this;
13161         }.overloadSetter(),
13162
13163         get: function(prop){
13164                 prop = prop.toLowerCase();
13165                 var method = DateMethods[prop] && 'get' + DateMethods[prop];
13166                 if (method && this[method]) return this[method]();
13167                 return null;
13168         }.overloadGetter(),
13169
13170         clone: function(){
13171                 return new Date(this.get('time'));
13172         },
13173
13174         increment: function(interval, times){
13175                 interval = interval || 'day';
13176                 times = times != null ? times : 1;
13177
13178                 switch (interval){
13179                         case 'year':
13180                                 return this.increment('month', times * 12);
13181                         case 'month':
13182                                 var d = this.get('date');
13183                                 this.set('date', 1).set('mo', this.get('mo') + times);
13184                                 return this.set('date', d.min(this.get('lastdayofmonth')));
13185                         case 'week':
13186                                 return this.increment('day', times * 7);
13187                         case 'day':
13188                                 return this.set('date', this.get('date') + times);
13189                 }
13190
13191                 if (!Date.units[interval]) throw new Error(interval + ' is not a supported interval');
13192
13193                 return this.set('time', this.get('time') + times * Date.units[interval]());
13194         },
13195
13196         decrement: function(interval, times){
13197                 return this.increment(interval, -1 * (times != null ? times : 1));
13198         },
13199
13200         isLeapYear: function(){
13201                 return Date.isLeapYear(this.get('year'));
13202         },
13203
13204         clearTime: function(){
13205                 return this.set({hr: 0, min: 0, sec: 0, ms: 0});
13206         },
13207
13208         diff: function(date, resolution){
13209                 if (typeOf(date) == 'string') date = Date.parse(date);
13210
13211                 return ((date - this) / Date.units[resolution || 'day'](3, 3)).round(); // non-leap year, 30-day month
13212         },
13213
13214         getLastDayOfMonth: function(){
13215                 return Date.daysInMonth(this.get('mo'), this.get('year'));
13216         },
13217
13218         getDayOfYear: function(){
13219                 return (Date.UTC(this.get('year'), this.get('mo'), this.get('date') + 1)
13220                         - Date.UTC(this.get('year'), 0, 1)) / Date.units.day();
13221         },
13222
13223         setDay: function(day, firstDayOfWeek){
13224                 if (firstDayOfWeek == null){
13225                         firstDayOfWeek = Date.getMsg('firstDayOfWeek');
13226                         if (firstDayOfWeek === '') firstDayOfWeek = 1;
13227                 }
13228
13229                 day = (7 + Date.parseDay(day, true) - firstDayOfWeek) % 7;
13230                 var currentDay = (7 + this.get('day') - firstDayOfWeek) % 7;
13231
13232                 return this.increment('day', day - currentDay);
13233         },
13234
13235         getWeek: function(firstDayOfWeek){
13236                 if (firstDayOfWeek == null){
13237                         firstDayOfWeek = Date.getMsg('firstDayOfWeek');
13238                         if (firstDayOfWeek === '') firstDayOfWeek = 1;
13239                 }
13240
13241                 var date = this,
13242                         dayOfWeek = (7 + date.get('day') - firstDayOfWeek) % 7,
13243                         dividend = 0,
13244                         firstDayOfYear;
13245
13246                 if (firstDayOfWeek == 1){
13247                         // ISO-8601, week belongs to year that has the most days of the week (i.e. has the thursday of the week)
13248                         var month = date.get('month'),
13249                                 startOfWeek = date.get('date') - dayOfWeek;
13250
13251                         if (month == 11 && startOfWeek > 28) return 1; // Week 1 of next year
13252
13253                         if (month == 0 && startOfWeek < -2){
13254                                 // Use a date from last year to determine the week
13255                                 date = new Date(date).decrement('day', dayOfWeek);
13256                                 dayOfWeek = 0;
13257                         }
13258
13259                         firstDayOfYear = new Date(date.get('year'), 0, 1).get('day') || 7;
13260                         if (firstDayOfYear > 4) dividend = -7; // First week of the year is not week 1
13261                 } else {
13262                         // In other cultures the first week of the year is always week 1 and the last week always 53 or 54.
13263                         // Days in the same week can have a different weeknumber if the week spreads across two years.
13264                         firstDayOfYear = new Date(date.get('year'), 0, 1).get('day');
13265                 }
13266
13267                 dividend += date.get('dayofyear');
13268                 dividend += 6 - dayOfWeek; // Add days so we calculate the current date's week as a full week
13269                 dividend += (7 + firstDayOfYear - firstDayOfWeek) % 7; // Make up for first week of the year not being a full week
13270
13271                 return (dividend / 7);
13272         },
13273
13274         getOrdinal: function(day){
13275                 return Date.getMsg('ordinal', day || this.get('date'));
13276         },
13277
13278         getTimezone: function(){
13279                 return this.toString()
13280                         .replace(/^.*? ([A-Z]{3}).[0-9]{4}.*$/, '$1')
13281                         .replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, '$1$2$3');
13282         },
13283
13284         getGMTOffset: function(){
13285                 var off = this.get('timezoneOffset');
13286                 return ((off > 0) ? '-' : '+') + pad((off.abs() / 60).floor(), 2) + pad(off % 60, 2);
13287         },
13288
13289         setAMPM: function(ampm){
13290                 ampm = ampm.toUpperCase();
13291                 var hr = this.get('hr');
13292                 if (hr > 11 && ampm == 'AM') return this.decrement('hour', 12);
13293                 else if (hr < 12 && ampm == 'PM') return this.increment('hour', 12);
13294                 return this;
13295         },
13296
13297         getAMPM: function(){
13298                 return (this.get('hr') < 12) ? 'AM' : 'PM';
13299         },
13300
13301         parse: function(str){
13302                 this.set('time', Date.parse(str));
13303                 return this;
13304         },
13305
13306         isValid: function(date){
13307                 if (!date) date = this;
13308                 return typeOf(date) == 'date' && !isNaN(date.valueOf());
13309         },
13310
13311         format: function(format){
13312                 if (!this.isValid()) return 'invalid date';
13313
13314                 if (!format) format = '%x %X';
13315                 if (typeof format == 'string') format = formats[format.toLowerCase()] || format;
13316                 if (typeof format == 'function') return format(this);
13317
13318                 var d = this;
13319                 return format.replace(/%([a-z%])/gi,
13320                         function($0, $1){
13321                                 switch ($1){
13322                                         case 'a': return Date.getMsg('days_abbr')[d.get('day')];
13323                                         case 'A': return Date.getMsg('days')[d.get('day')];
13324                                         case 'b': return Date.getMsg('months_abbr')[d.get('month')];
13325                                         case 'B': return Date.getMsg('months')[d.get('month')];
13326                                         case 'c': return d.format('%a %b %d %H:%M:%S %Y');
13327                                         case 'd': return pad(d.get('date'), 2);
13328                                         case 'e': return pad(d.get('date'), 2, ' ');
13329                                         case 'H': return pad(d.get('hr'), 2);
13330                                         case 'I': return pad((d.get('hr') % 12) || 12, 2);
13331                                         case 'j': return pad(d.get('dayofyear'), 3);
13332                                         case 'k': return pad(d.get('hr'), 2, ' ');
13333                                         case 'l': return pad((d.get('hr') % 12) || 12, 2, ' ');
13334                                         case 'L': return pad(d.get('ms'), 3);
13335                                         case 'm': return pad((d.get('mo') + 1), 2);
13336                                         case 'M': return pad(d.get('min'), 2);
13337                                         case 'o': return d.get('ordinal');
13338                                         case 'p': return Date.getMsg(d.get('ampm'));
13339                                         case 's': return Math.round(d / 1000);
13340                                         case 'S': return pad(d.get('seconds'), 2);
13341                                         case 'T': return d.format('%H:%M:%S');
13342                                         case 'U': return pad(d.get('week'), 2);
13343                                         case 'w': return d.get('day');
13344                                         case 'x': return d.format(Date.getMsg('shortDate'));
13345                                         case 'X': return d.format(Date.getMsg('shortTime'));
13346                                         case 'y': return d.get('year').toString().substr(2);
13347                                         case 'Y': return d.get('year');
13348                                         case 'z': return d.get('GMTOffset');
13349                                         case 'Z': return d.get('Timezone');
13350                                 }
13351                                 return $1;
13352                         }
13353                 );
13354         },
13355
13356         toISOString: function(){
13357                 return this.format('iso8601');
13358         }
13359
13360 }).alias({
13361         toJSON: 'toISOString',
13362         compare: 'diff',
13363         strftime: 'format'
13364 });
13365
13366 // The day and month abbreviations are standardized, so we cannot use simply %a and %b because they will get localized
13367 var rfcDayAbbr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
13368         rfcMonthAbbr = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
13369
13370 var formats = {
13371         db: '%Y-%m-%d %H:%M:%S',
13372         compact: '%Y%m%dT%H%M%S',
13373         'short': '%d %b %H:%M',
13374         'long': '%B %d, %Y %H:%M',
13375         rfc822: function(date){
13376                 return rfcDayAbbr[date.get('day')] + date.format(', %d ') + rfcMonthAbbr[date.get('month')] + date.format(' %Y %H:%M:%S %Z');
13377         },
13378         rfc2822: function(date){
13379                 return rfcDayAbbr[date.get('day')] + date.format(', %d ') + rfcMonthAbbr[date.get('month')] + date.format(' %Y %H:%M:%S %z');
13380         },
13381         iso8601: function(date){
13382                 return (
13383                         date.getUTCFullYear() + '-' +
13384                         pad(date.getUTCMonth() + 1, 2) + '-' +
13385                         pad(date.getUTCDate(), 2) + 'T' +
13386                         pad(date.getUTCHours(), 2) + ':' +
13387                         pad(date.getUTCMinutes(), 2) + ':' +
13388                         pad(date.getUTCSeconds(), 2) + '.' +
13389                         pad(date.getUTCMilliseconds(), 3) + 'Z'
13390                 );
13391         }
13392 };
13393
13394 var parsePatterns = [],
13395         nativeParse = Date.parse;
13396
13397 var parseWord = function(type, word, num){
13398         var ret = -1,
13399                 translated = Date.getMsg(type + 's');
13400         switch (typeOf(word)){
13401                 case 'object':
13402                         ret = translated[word.get(type)];
13403                         break;
13404                 case 'number':
13405                         ret = translated[word];
13406                         if (!ret) throw new Error('Invalid ' + type + ' index: ' + word);
13407                         break;
13408                 case 'string':
13409                         var match = translated.filter(function(name){
13410                                 return this.test(name);
13411                         }, new RegExp('^' + word, 'i'));
13412                         if (!match.length) throw new Error('Invalid ' + type + ' string');
13413                         if (match.length > 1) throw new Error('Ambiguous ' + type);
13414                         ret = match[0];
13415         }
13416
13417         return (num) ? translated.indexOf(ret) : ret;
13418 };
13419
13420 var startCentury = 1900,
13421         startYear = 70;
13422
13423 Date.extend({
13424
13425         getMsg: function(key, args){
13426                 return Locale.get('Date.' + key, args);
13427         },
13428
13429         units: {
13430                 ms: Function.from(1),
13431                 second: Function.from(1000),
13432                 minute: Function.from(60000),
13433                 hour: Function.from(3600000),
13434                 day: Function.from(86400000),
13435                 week: Function.from(608400000),
13436                 month: function(month, year){
13437                         var d = new Date;
13438                         return Date.daysInMonth(month != null ? month : d.get('mo'), year != null ? year : d.get('year')) * 86400000;
13439                 },
13440                 year: function(year){
13441                         year = year || new Date().get('year');
13442                         return Date.isLeapYear(year) ? 31622400000 : 31536000000;
13443                 }
13444         },
13445
13446         daysInMonth: function(month, year){
13447                 return [31, Date.isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
13448         },
13449
13450         isLeapYear: function(year){
13451                 return ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
13452         },
13453
13454         parse: function(from){
13455                 var t = typeOf(from);
13456                 if (t == 'number') return new Date(from);
13457                 if (t != 'string') return from;
13458                 from = from.clean();
13459                 if (!from.length) return null;
13460
13461                 var parsed;
13462                 parsePatterns.some(function(pattern){
13463                         var bits = pattern.re.exec(from);
13464                         return (bits) ? (parsed = pattern.handler(bits)) : false;
13465                 });
13466
13467                 if (!(parsed && parsed.isValid())){
13468                         parsed = new Date(nativeParse(from));
13469                         if (!(parsed && parsed.isValid())) parsed = new Date(from.toInt());
13470                 }
13471                 return parsed;
13472         },
13473
13474         parseDay: function(day, num){
13475                 return parseWord('day', day, num);
13476         },
13477
13478         parseMonth: function(month, num){
13479                 return parseWord('month', month, num);
13480         },
13481
13482         parseUTC: function(value){
13483                 var localDate = new Date(value);
13484                 var utcSeconds = Date.UTC(
13485                         localDate.get('year'),
13486                         localDate.get('mo'),
13487                         localDate.get('date'),
13488                         localDate.get('hr'),
13489                         localDate.get('min'),
13490                         localDate.get('sec'),
13491                         localDate.get('ms')
13492                 );
13493                 return new Date(utcSeconds);
13494         },
13495
13496         orderIndex: function(unit){
13497                 return Date.getMsg('dateOrder').indexOf(unit) + 1;
13498         },
13499
13500         defineFormat: function(name, format){
13501                 formats[name] = format;
13502                 return this;
13503         },
13504
13505         //<1.2compat>
13506         parsePatterns: parsePatterns,
13507         //</1.2compat>
13508
13509         defineParser: function(pattern){
13510                 parsePatterns.push((pattern.re && pattern.handler) ? pattern : build(pattern));
13511                 return this;
13512         },
13513
13514         defineParsers: function(){
13515                 Array.flatten(arguments).each(Date.defineParser);
13516                 return this;
13517         },
13518
13519         define2DigitYearStart: function(year){
13520                 startYear = year % 100;
13521                 startCentury = year - startYear;
13522                 return this;
13523         }
13524
13525 }).extend({
13526         defineFormats: Date.defineFormat.overloadSetter()
13527 });
13528
13529 var regexOf = function(type){
13530         return new RegExp('(?:' + Date.getMsg(type).map(function(name){
13531                 return name.substr(0, 3);
13532         }).join('|') + ')[a-z]*');
13533 };
13534
13535 var replacers = function(key){
13536         switch (key){
13537                 case 'T':
13538                         return '%H:%M:%S';
13539                 case 'x': // iso8601 covers yyyy-mm-dd, so just check if month is first
13540                         return ((Date.orderIndex('month') == 1) ? '%m[-./]%d' : '%d[-./]%m') + '([-./]%y)?';
13541                 case 'X':
13542                         return '%H([.:]%M)?([.:]%S([.:]%s)?)? ?%p? ?%z?';
13543         }
13544         return null;
13545 };
13546
13547 var keys = {
13548         d: /[0-2]?[0-9]|3[01]/,
13549         H: /[01]?[0-9]|2[0-3]/,
13550         I: /0?[1-9]|1[0-2]/,
13551         M: /[0-5]?\d/,
13552         s: /\d+/,
13553         o: /[a-z]*/,
13554         p: /[ap]\.?m\.?/,
13555         y: /\d{2}|\d{4}/,
13556         Y: /\d{4}/,
13557         z: /Z|[+-]\d{2}(?::?\d{2})?/
13558 };
13559
13560 keys.m = keys.I;
13561 keys.S = keys.M;
13562
13563 var currentLanguage;
13564
13565 var recompile = function(language){
13566         currentLanguage = language;
13567
13568         keys.a = keys.A = regexOf('days');
13569         keys.b = keys.B = regexOf('months');
13570
13571         parsePatterns.each(function(pattern, i){
13572                 if (pattern.format) parsePatterns[i] = build(pattern.format);
13573         });
13574 };
13575
13576 var build = function(format){
13577         if (!currentLanguage) return {format: format};
13578
13579         var parsed = [];
13580         var re = (format.source || format) // allow format to be regex
13581          .replace(/%([a-z])/gi,
13582                 function($0, $1){
13583                         return replacers($1) || $0;
13584                 }
13585         ).replace(/\((?!\?)/g, '(?:') // make all groups non-capturing
13586          .replace(/ (?!\?|\*)/g, ',? ') // be forgiving with spaces and commas
13587          .replace(/%([a-z%])/gi,
13588                 function($0, $1){
13589                         var p = keys[$1];
13590                         if (!p) return $1;
13591                         parsed.push($1);
13592                         return '(' + p.source + ')';
13593                 }
13594         ).replace(/\[a-z\]/gi, '[a-z\\u00c0-\\uffff;\&]'); // handle unicode words
13595
13596         return {
13597                 format: format,
13598                 re: new RegExp('^' + re + '$', 'i'),
13599                 handler: function(bits){
13600                         bits = bits.slice(1).associate(parsed);
13601                         var date = new Date().clearTime(),
13602                                 year = bits.y || bits.Y;
13603
13604                         if (year != null) handle.call(date, 'y', year); // need to start in the right year
13605                         if ('d' in bits) handle.call(date, 'd', 1);
13606                         if ('m' in bits || bits.b || bits.B) handle.call(date, 'm', 1);
13607
13608                         for (var key in bits) handle.call(date, key, bits[key]);
13609                         return date;
13610                 }
13611         };
13612 };
13613
13614 var handle = function(key, value){
13615         if (!value) return this;
13616
13617         switch (key){
13618                 case 'a': case 'A': return this.set('day', Date.parseDay(value, true));
13619                 case 'b': case 'B': return this.set('mo', Date.parseMonth(value, true));
13620                 case 'd': return this.set('date', value);
13621                 case 'H': case 'I': return this.set('hr', value);
13622                 case 'm': return this.set('mo', value - 1);
13623                 case 'M': return this.set('min', value);
13624                 case 'p': return this.set('ampm', value.replace(/\./g, ''));
13625                 case 'S': return this.set('sec', value);
13626                 case 's': return this.set('ms', ('0.' + value) * 1000);
13627                 case 'w': return this.set('day', value);
13628                 case 'Y': return this.set('year', value);
13629                 case 'y':
13630                         value = +value;
13631                         if (value < 100) value += startCentury + (value < startYear ? 100 : 0);
13632                         return this.set('year', value);
13633                 case 'z':
13634                         if (value == 'Z') value = '+00';
13635                         var offset = value.match(/([+-])(\d{2}):?(\d{2})?/);
13636                         offset = (offset[1] + '1') * (offset[2] * 60 + (+offset[3] || 0)) + this.getTimezoneOffset();
13637                         return this.set('time', this - offset * 60000);
13638         }
13639
13640         return this;
13641 };
13642
13643 Date.defineParsers(
13644         '%Y([-./]%m([-./]%d((T| )%X)?)?)?', // "1999-12-31", "1999-12-31 11:59pm", "1999-12-31 23:59:59", ISO8601
13645         '%Y%m%d(T%H(%M%S?)?)?', // "19991231", "19991231T1159", compact
13646         '%x( %X)?', // "12/31", "12.31.99", "12-31-1999", "12/31/2008 11:59 PM"
13647         '%d%o( %b( %Y)?)?( %X)?', // "31st", "31st December", "31 Dec 1999", "31 Dec 1999 11:59pm"
13648         '%b( %d%o)?( %Y)?( %X)?', // Same as above with month and day switched
13649         '%Y %b( %d%o( %X)?)?', // Same as above with year coming first
13650         '%o %b %d %X %z %Y', // "Thu Oct 22 08:11:23 +0000 2009"
13651         '%T', // %H:%M:%S
13652         '%H:%M( ?%p)?' // "11:05pm", "11:05 am" and "11:05"
13653 );
13654
13655 Locale.addEvent('change', function(language){
13656         if (Locale.get('Date')) recompile(language);
13657 }).fireEvent('change', Locale.getCurrent());
13658
13659 })();
13660
13661
13662 // Begin: Source/Types/Date.Extras.js
13663 /*
13664 ---
13665
13666 script: Date.Extras.js
13667
13668 name: Date.Extras
13669
13670 description: Extends the Date native object to include extra methods (on top of those in Date.js).
13671
13672 license: MIT-style license
13673
13674 authors:
13675   - Aaron Newton
13676   - Scott Kyle
13677
13678 requires:
13679   - /Date
13680
13681 provides: [Date.Extras]
13682
13683 ...
13684 */
13685
13686 Date.implement({
13687
13688         timeDiffInWords: function(to){
13689                 return Date.distanceOfTimeInWords(this, to || new Date);
13690         },
13691
13692         timeDiff: function(to, separator){
13693                 if (to == null) to = new Date;
13694                 var delta = ((to - this) / 1000).floor().abs();
13695
13696                 var vals = [],
13697                         durations = [60, 60, 24, 365, 0],
13698                         names = ['s', 'm', 'h', 'd', 'y'],
13699                         value, duration;
13700
13701                 for (var item = 0; item < durations.length; item++){
13702                         if (item && !delta) break;
13703                         value = delta;
13704                         if ((duration = durations[item])){
13705                                 value = (delta % duration);
13706                                 delta = (delta / duration).floor();
13707                         }
13708                         vals.unshift(value + (names[item] || ''));
13709                 }
13710
13711                 return vals.join(separator || ':');
13712         }
13713
13714 }).extend({
13715
13716         distanceOfTimeInWords: function(from, to){
13717                 return Date.getTimePhrase(((to - from) / 1000).toInt());
13718         },
13719
13720         getTimePhrase: function(delta){
13721                 var suffix = (delta < 0) ? 'Until' : 'Ago';
13722                 if (delta < 0) delta *= -1;
13723
13724                 var units = {
13725                         minute: 60,
13726                         hour: 60,
13727                         day: 24,
13728                         week: 7,
13729                         month: 52 / 12,
13730                         year: 12,
13731                         eon: Infinity
13732                 };
13733
13734                 var msg = 'lessThanMinute';
13735
13736                 for (var unit in units){
13737                         var interval = units[unit];
13738                         if (delta < 1.5 * interval){
13739                                 if (delta > 0.75 * interval) msg = unit;
13740                                 break;
13741                         }
13742                         delta /= interval;
13743                         msg = unit + 's';
13744                 }
13745
13746                 delta = delta.round();
13747                 return Date.getMsg(msg + suffix, delta).substitute({delta: delta});
13748         }
13749
13750 }).defineParsers(
13751
13752         {
13753                 // "today", "tomorrow", "yesterday"
13754                 re: /^(?:tod|tom|yes)/i,
13755                 handler: function(bits){
13756                         var d = new Date().clearTime();
13757                         switch (bits[0]){
13758                                 case 'tom': return d.increment();
13759                                 case 'yes': return d.decrement();
13760                                 default: return d;
13761                         }
13762                 }
13763         },
13764
13765         {
13766                 // "next Wednesday", "last Thursday"
13767                 re: /^(next|last) ([a-z]+)$/i,
13768                 handler: function(bits){
13769                         var d = new Date().clearTime();
13770                         var day = d.getDay();
13771                         var newDay = Date.parseDay(bits[2], true);
13772                         var addDays = newDay - day;
13773                         if (newDay <= day) addDays += 7;
13774                         if (bits[1] == 'last') addDays -= 7;
13775                         return d.set('date', d.getDate() + addDays);
13776                 }
13777         }
13778
13779 ).alias('timeAgoInWords', 'timeDiffInWords');
13780
13781
13782 // Begin: Source/Fx/Fx.Elements.js
13783 /*
13784 ---
13785
13786 script: Fx.Elements.js
13787
13788 name: Fx.Elements
13789
13790 description: Effect to change any number of CSS properties of any number of Elements.
13791
13792 license: MIT-style license
13793
13794 authors:
13795   - Valerio Proietti
13796
13797 requires:
13798   - Core/Fx.CSS
13799   - /MooTools.More
13800
13801 provides: [Fx.Elements]
13802
13803 ...
13804 */
13805
13806 Fx.Elements = new Class({
13807
13808         Extends: Fx.CSS,
13809
13810         initialize: function(elements, options){
13811                 this.elements = this.subject = $$(elements);
13812                 this.parent(options);
13813         },
13814
13815         compute: function(from, to, delta){
13816                 var now = {};
13817
13818                 for (var i in from){
13819                         var iFrom = from[i], iTo = to[i], iNow = now[i] = {};
13820                         for (var p in iFrom) iNow[p] = this.parent(iFrom[p], iTo[p], delta);
13821                 }
13822
13823                 return now;
13824         },
13825
13826         set: function(now){
13827                 for (var i in now){
13828                         if (!this.elements[i]) continue;
13829
13830                         var iNow = now[i];
13831                         for (var p in iNow) this.render(this.elements[i], p, iNow[p], this.options.unit);
13832                 }
13833
13834                 return this;
13835         },
13836
13837         start: function(obj){
13838                 if (!this.check(obj)) return this;
13839                 var from = {}, to = {};
13840
13841                 for (var i in obj){
13842                         if (!this.elements[i]) continue;
13843
13844                         var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {};
13845
13846                         for (var p in iProps){
13847                                 var parsed = this.prepare(this.elements[i], p, iProps[p]);
13848                                 iFrom[p] = parsed.from;
13849                                 iTo[p] = parsed.to;
13850                         }
13851                 }
13852
13853                 return this.parent(from, to);
13854         }
13855
13856 });
13857
13858
13859 // Begin: Source/Fx/Fx.Accordion.js
13860 /*
13861 ---
13862
13863 script: Fx.Accordion.js
13864
13865 name: Fx.Accordion
13866
13867 description: An Fx.Elements extension which allows you to easily create accordion type controls.
13868
13869 license: MIT-style license
13870
13871 authors:
13872   - Valerio Proietti
13873
13874 requires:
13875   - Core/Element.Event
13876   - /Fx.Elements
13877
13878 provides: [Fx.Accordion]
13879
13880 ...
13881 */
13882
13883 Fx.Accordion = new Class({
13884
13885         Extends: Fx.Elements,
13886
13887         options: {/*
13888                 onActive: function(toggler, section){},
13889                 onBackground: function(toggler, section){},*/
13890                 fixedHeight: false,
13891                 fixedWidth: false,
13892                 display: 0,
13893                 show: false,
13894                 height: true,
13895                 width: false,
13896                 opacity: true,
13897                 alwaysHide: false,
13898                 trigger: 'click',
13899                 initialDisplayFx: true,
13900                 resetHeight: true
13901         },
13902
13903         initialize: function(){
13904                 var defined = function(obj){
13905                         return obj != null;
13906                 };
13907
13908                 var params = Array.link(arguments, {
13909                         'container': Type.isElement, //deprecated
13910                         'options': Type.isObject,
13911                         'togglers': defined,
13912                         'elements': defined
13913                 });
13914                 this.parent(params.elements, params.options);
13915
13916                 var options = this.options,
13917                         togglers = this.togglers = $$(params.togglers);
13918
13919                 this.previous = -1;
13920                 this.internalChain = new Chain();
13921
13922                 if (options.alwaysHide) this.options.link = 'chain';
13923
13924                 if (options.show || this.options.show === 0){
13925                         options.display = false;
13926                         this.previous = options.show;
13927                 }
13928
13929                 if (options.start){
13930                         options.display = false;
13931                         options.show = false;
13932                 }
13933
13934                 var effects = this.effects = {};
13935
13936                 if (options.opacity) effects.opacity = 'fullOpacity';
13937                 if (options.width) effects.width = options.fixedWidth ? 'fullWidth' : 'offsetWidth';
13938                 if (options.height) effects.height = options.fixedHeight ? 'fullHeight' : 'scrollHeight';
13939
13940                 for (var i = 0, l = togglers.length; i < l; i++) this.addSection(togglers[i], this.elements[i]);
13941
13942                 this.elements.each(function(el, i){
13943                         if (options.show === i){
13944                                 this.fireEvent('active', [togglers[i], el]);
13945                         } else {
13946                                 for (var fx in effects) el.setStyle(fx, 0);
13947                         }
13948                 }, this);
13949
13950                 if (options.display || options.display === 0 || options.initialDisplayFx === false){
13951                         this.display(options.display, options.initialDisplayFx);
13952                 }
13953
13954                 if (options.fixedHeight !== false) options.resetHeight = false;
13955                 this.addEvent('complete', this.internalChain.callChain.bind(this.internalChain));
13956         },
13957
13958         addSection: function(toggler, element){
13959                 toggler = document.id(toggler);
13960                 element = document.id(element);
13961                 this.togglers.include(toggler);
13962                 this.elements.include(element);
13963
13964                 var togglers = this.togglers,
13965                         options = this.options,
13966                         test = togglers.contains(toggler),
13967                         idx = togglers.indexOf(toggler),
13968                         displayer = this.display.pass(idx, this);
13969
13970                 toggler.store('accordion:display', displayer)
13971                         .addEvent(options.trigger, displayer);
13972
13973                 if (options.height) element.setStyles({'padding-top': 0, 'border-top': 'none', 'padding-bottom': 0, 'border-bottom': 'none'});
13974                 if (options.width) element.setStyles({'padding-left': 0, 'border-left': 'none', 'padding-right': 0, 'border-right': 'none'});
13975
13976                 element.fullOpacity = 1;
13977                 if (options.fixedWidth) element.fullWidth = options.fixedWidth;
13978                 if (options.fixedHeight) element.fullHeight = options.fixedHeight;
13979                 element.setStyle('overflow', 'hidden');
13980
13981                 if (!test) for (var fx in this.effects){
13982                         element.setStyle(fx, 0);
13983                 }
13984                 return this;
13985         },
13986
13987         removeSection: function(toggler, displayIndex){
13988                 var togglers = this.togglers,
13989                         idx = togglers.indexOf(toggler),
13990                         element = this.elements[idx];
13991
13992                 var remover = function(){
13993                         togglers.erase(toggler);
13994                         this.elements.erase(element);
13995                         this.detach(toggler);
13996                 }.bind(this);
13997
13998                 if (this.now == idx || displayIndex != null){
13999                         this.display(displayIndex != null ? displayIndex : (idx - 1 >= 0 ? idx - 1 : 0)).chain(remover);
14000                 } else {
14001                         remover();
14002                 }
14003                 return this;
14004         },
14005
14006         detach: function(toggler){
14007                 var remove = function(toggler){
14008                         toggler.removeEvent(this.options.trigger, toggler.retrieve('accordion:display'));
14009                 }.bind(this);
14010
14011                 if (!toggler) this.togglers.each(remove);
14012                 else remove(toggler);
14013                 return this;
14014         },
14015
14016         display: function(index, useFx){
14017                 if (!this.check(index, useFx)) return this;
14018
14019                 var obj = {},
14020                         elements = this.elements,
14021                         options = this.options,
14022                         effects = this.effects;
14023
14024                 if (useFx == null) useFx = true;
14025                 if (typeOf(index) == 'element') index = elements.indexOf(index);
14026                 if (index == this.previous && !options.alwaysHide) return this;
14027
14028                 if (options.resetHeight){
14029                         var prev = elements[this.previous];
14030                         if (prev && !this.selfHidden){
14031                                 for (var fx in effects) prev.setStyle(fx, prev[effects[fx]]);
14032                         }
14033                 }
14034
14035                 if ((this.timer && options.link == 'chain') || (index === this.previous && !options.alwaysHide)) return this;
14036
14037                 this.previous = index;
14038                 this.selfHidden = false;
14039
14040                 elements.each(function(el, i){
14041                         obj[i] = {};
14042                         var hide;
14043                         if (i != index){
14044                                 hide = true;
14045                         } else if (options.alwaysHide && ((el.offsetHeight > 0 && options.height) || el.offsetWidth > 0 && options.width)){
14046                                 hide = true;
14047                                 this.selfHidden = true;
14048                         }
14049                         this.fireEvent(hide ? 'background' : 'active', [this.togglers[i], el]);
14050                         for (var fx in effects) obj[i][fx] = hide ? 0 : el[effects[fx]];
14051                         if (!useFx && !hide && options.resetHeight) obj[i].height = 'auto';
14052                 }, this);
14053
14054                 this.internalChain.clearChain();
14055                 this.internalChain.chain(function(){
14056                         if (options.resetHeight && !this.selfHidden){
14057                                 var el = elements[index];
14058                                 if (el) el.setStyle('height', 'auto');
14059                         }
14060                 }.bind(this));
14061
14062                 return useFx ? this.start(obj) : this.set(obj).internalChain.callChain();
14063         }
14064
14065 });
14066
14067 /*<1.2compat>*/
14068 /*
14069         Compatibility with 1.2.0
14070 */
14071 var Accordion = new Class({
14072
14073         Extends: Fx.Accordion,
14074
14075         initialize: function(){
14076                 this.parent.apply(this, arguments);
14077                 var params = Array.link(arguments, {'container': Type.isElement});
14078                 this.container = params.container;
14079         },
14080
14081         addSection: function(toggler, element, pos){
14082                 toggler = document.id(toggler);
14083                 element = document.id(element);
14084
14085                 var test = this.togglers.contains(toggler);
14086                 var len = this.togglers.length;
14087                 if (len && (!test || pos)){
14088                         pos = pos != null ? pos : len - 1;
14089                         toggler.inject(this.togglers[pos], 'before');
14090                         element.inject(toggler, 'after');
14091                 } else if (this.container && !test){
14092                         toggler.inject(this.container);
14093                         element.inject(this.container);
14094                 }
14095                 return this.parent.apply(this, arguments);
14096         }
14097
14098 });
14099 /*</1.2compat>*/
14100
14101
14102 // Begin: Source/Types/Hash.js
14103 /*
14104 ---
14105
14106 name: Hash
14107
14108 description: Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects.
14109
14110 license: MIT-style license.
14111
14112 requires:
14113   - Core/Object
14114   - /MooTools.More
14115
14116 provides: [Hash]
14117
14118 ...
14119 */
14120
14121 (function(){
14122
14123 if (this.Hash) return;
14124
14125 var Hash = this.Hash = new Type('Hash', function(object){
14126         if (typeOf(object) == 'hash') object = Object.clone(object.getClean());
14127         for (var key in object) this[key] = object[key];
14128         return this;
14129 });
14130
14131 this.$H = function(object){
14132         return new Hash(object);
14133 };
14134
14135 Hash.implement({
14136
14137         forEach: function(fn, bind){
14138                 Object.forEach(this, fn, bind);
14139         },
14140
14141         getClean: function(){
14142                 var clean = {};
14143                 for (var key in this){
14144                         if (this.hasOwnProperty(key)) clean[key] = this[key];
14145                 }
14146                 return clean;
14147         },
14148
14149         getLength: function(){
14150                 var length = 0;
14151                 for (var key in this){
14152                         if (this.hasOwnProperty(key)) length++;
14153                 }
14154                 return length;
14155         }
14156
14157 });
14158
14159 Hash.alias('each', 'forEach');
14160
14161 Hash.implement({
14162
14163         has: Object.prototype.hasOwnProperty,
14164
14165         keyOf: function(value){
14166                 return Object.keyOf(this, value);
14167         },
14168
14169         hasValue: function(value){
14170                 return Object.contains(this, value);
14171         },
14172
14173         extend: function(properties){
14174                 Hash.each(properties || {}, function(value, key){
14175                         Hash.set(this, key, value);
14176                 }, this);
14177                 return this;
14178         },
14179
14180         combine: function(properties){
14181                 Hash.each(properties || {}, function(value, key){
14182                         Hash.include(this, key, value);
14183                 }, this);
14184                 return this;
14185         },
14186
14187         erase: function(key){
14188                 if (this.hasOwnProperty(key)) delete this[key];
14189                 return this;
14190         },
14191
14192         get: function(key){
14193                 return (this.hasOwnProperty(key)) ? this[key] : null;
14194         },
14195
14196         set: function(key, value){
14197                 if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
14198                 return this;
14199         },
14200
14201         empty: function(){
14202                 Hash.each(this, function(value, key){
14203                         delete this[key];
14204                 }, this);
14205                 return this;
14206         },
14207
14208         include: function(key, value){
14209                 if (this[key] == undefined) this[key] = value;
14210                 return this;
14211         },
14212
14213         map: function(fn, bind){
14214                 return new Hash(Object.map(this, fn, bind));
14215         },
14216
14217         filter: function(fn, bind){
14218                 return new Hash(Object.filter(this, fn, bind));
14219         },
14220
14221         every: function(fn, bind){
14222                 return Object.every(this, fn, bind);
14223         },
14224
14225         some: function(fn, bind){
14226                 return Object.some(this, fn, bind);
14227         },
14228
14229         getKeys: function(){
14230                 return Object.keys(this);
14231         },
14232
14233         getValues: function(){
14234                 return Object.values(this);
14235         },
14236
14237         toQueryString: function(base){
14238                 return Object.toQueryString(this, base);
14239         }
14240
14241 });
14242
14243 Hash.alias({indexOf: 'keyOf', contains: 'hasValue'});
14244
14245
14246 })();
14247
14248
14249
14250 // Begin: Source/Utilities/Hash.Cookie.js
14251 /*
14252 ---
14253
14254 script: Hash.Cookie.js
14255
14256 name: Hash.Cookie
14257
14258 description: Class for creating, reading, and deleting Cookies in JSON format.
14259
14260 license: MIT-style license
14261
14262 authors:
14263   - Valerio Proietti
14264   - Aaron Newton
14265
14266 requires:
14267   - Core/Cookie
14268   - Core/JSON
14269   - /MooTools.More
14270   - /Hash
14271
14272 provides: [Hash.Cookie]
14273
14274 ...
14275 */
14276
14277 Hash.Cookie = new Class({
14278
14279         Extends: Cookie,
14280
14281         options: {
14282                 autoSave: true
14283         },
14284
14285         initialize: function(name, options){
14286                 this.parent(name, options);
14287                 this.load();
14288         },
14289
14290         save: function(){
14291                 var value = JSON.encode(this.hash);
14292                 if (!value || value.length > 4096) return false; //cookie would be truncated!
14293                 if (value == '{}') this.dispose();
14294                 else this.write(value);
14295                 return true;
14296         },
14297
14298         load: function(){
14299                 this.hash = new Hash(JSON.decode(this.read(), true));
14300                 return this;
14301         }
14302
14303 });
14304
14305 Hash.each(Hash.prototype, function(method, name){
14306         if (typeof method == 'function') Hash.Cookie.implement(name, function(){
14307                 var value = method.apply(this.hash, arguments);
14308                 if (this.options.autoSave) this.save();
14309                 return value;
14310         });
14311 });
14312
14313
14314 // Begin: Source/Utilities/Assets.js
14315 /*
14316 ---
14317
14318 script: Assets.js
14319
14320 name: Assets
14321
14322 description: Provides methods to dynamically load JavaScript, CSS, and Image files into the document.
14323
14324 license: MIT-style license
14325
14326 authors:
14327   - Valerio Proietti
14328
14329 requires:
14330   - Core/Element.Event
14331   - /MooTools.More
14332
14333 provides: [Assets]
14334
14335 ...
14336 */
14337
14338 var Asset = {
14339
14340         javascript: function(source, properties){
14341                 if (!properties) properties = {};
14342
14343                 var script = new Element('script', {src: source, type: 'text/javascript'}),
14344                         doc = properties.document || document,
14345                         load = properties.onload || properties.onLoad;
14346
14347                 delete properties.onload;
14348                 delete properties.onLoad;
14349                 delete properties.document;
14350
14351                 if (load){
14352                         if (!script.addEventListener){
14353                                 script.addEvent('readystatechange', function(){
14354                                         if (['loaded', 'complete'].contains(this.readyState)) load.call(this);
14355                                 });
14356                         } else {
14357                                 script.addEvent('load', load);
14358                         }
14359                 }
14360
14361                 return script.set(properties).inject(doc.head);
14362         },
14363
14364         css: function(source, properties){
14365                 if (!properties) properties = {};
14366
14367                 var link = new Element('link', {
14368                         rel: 'stylesheet',
14369                         media: 'screen',
14370                         type: 'text/css',
14371                         href: source
14372                 });
14373
14374                 var load = properties.onload || properties.onLoad,
14375                         doc = properties.document || document;
14376
14377                 delete properties.onload;
14378                 delete properties.onLoad;
14379                 delete properties.document;
14380
14381                 if (load) link.addEvent('load', load);
14382                 return link.set(properties).inject(doc.head);
14383         },
14384
14385         image: function(source, properties){
14386                 if (!properties) properties = {};
14387
14388                 var image = new Image(),
14389                         element = document.id(image) || new Element('img');
14390
14391                 ['load', 'abort', 'error'].each(function(name){
14392                         var type = 'on' + name,
14393                                 cap = 'on' + name.capitalize(),
14394                                 event = properties[type] || properties[cap] || function(){};
14395
14396                         delete properties[cap];
14397                         delete properties[type];
14398
14399                         image[type] = function(){
14400                                 if (!image) return;
14401                                 if (!element.parentNode){
14402                                         element.width = image.width;
14403                                         element.height = image.height;
14404                                 }
14405                                 image = image.onload = image.onabort = image.onerror = null;
14406                                 event.delay(1, element, element);
14407                                 element.fireEvent(name, element, 1);
14408                         };
14409                 });
14410
14411                 image.src = element.src = source;
14412                 if (image && image.complete) image.onload.delay(1);
14413                 return element.set(properties);
14414         },
14415
14416         images: function(sources, options){
14417                 sources = Array.from(sources);
14418
14419                 var fn = function(){},
14420                         counter = 0;
14421
14422                 options = Object.merge({
14423                         onComplete: fn,
14424                         onProgress: fn,
14425                         onError: fn,
14426                         properties: {}
14427                 }, options);
14428
14429                 return new Elements(sources.map(function(source, index){
14430                         return Asset.image(source, Object.append(options.properties, {
14431                                 onload: function(){
14432                                         counter++;
14433                                         options.onProgress.call(this, counter, index, source);
14434                                         if (counter == sources.length) options.onComplete();
14435                                 },
14436                                 onerror: function(){
14437                                         counter++;
14438                                         options.onError.call(this, counter, index, source);
14439                                         if (counter == sources.length) options.onComplete();
14440                                 }
14441                         }));
14442                 }));
14443         }
14444
14445 };
14446
14447
14448 // Begin: Source/Interface/Spinner.js
14449 /*
14450 ---
14451
14452 script: Spinner.js
14453
14454 name: Spinner
14455
14456 description: Adds a semi-transparent overlay over a dom element with a spinnin ajax icon.
14457
14458 license: MIT-style license
14459
14460 authors:
14461   - Aaron Newton
14462
14463 requires:
14464   - Core/Fx.Tween
14465   - Core/Request
14466   - /Class.refactor
14467   - /Mask
14468
14469 provides: [Spinner]
14470
14471 ...
14472 */
14473
14474 var Spinner = new Class({
14475
14476         Extends: Mask,
14477
14478         Implements: Chain,
14479
14480         options: {/*
14481                 message: false,*/
14482                 'class': 'spinner',
14483                 containerPosition: {},
14484                 content: {
14485                         'class': 'spinner-content'
14486                 },
14487                 messageContainer: {
14488                         'class': 'spinner-msg'
14489                 },
14490                 img: {
14491                         'class': 'spinner-img'
14492                 },
14493                 fxOptions: {
14494                         link: 'chain'
14495                 }
14496         },
14497
14498         initialize: function(target, options){
14499                 this.target = document.id(target) || document.id(document.body);
14500                 this.target.store('spinner', this);
14501                 this.setOptions(options);
14502                 this.render();
14503                 this.inject();
14504
14505                 // Add this to events for when noFx is true; parent methods handle hide/show.
14506                 var deactivate = function(){ this.active = false; }.bind(this);
14507                 this.addEvents({
14508                         hide: deactivate,
14509                         show: deactivate
14510                 });
14511         },
14512
14513         render: function(){
14514                 this.parent();
14515
14516                 this.element.set('id', this.options.id || 'spinner-' + String.uniqueID());
14517
14518                 this.content = document.id(this.options.content) || new Element('div', this.options.content);
14519                 this.content.inject(this.element);
14520
14521                 if (this.options.message){
14522                         this.msg = document.id(this.options.message) || new Element('p', this.options.messageContainer).appendText(this.options.message);
14523                         this.msg.inject(this.content);
14524                 }
14525
14526                 if (this.options.img){
14527                         this.img = document.id(this.options.img) || new Element('div', this.options.img);
14528                         this.img.inject(this.content);
14529                 }
14530
14531                 this.element.set('tween', this.options.fxOptions);
14532         },
14533
14534         show: function(noFx){
14535                 if (this.active) return this.chain(this.show.bind(this));
14536                 if (!this.hidden){
14537                         this.callChain.delay(20, this);
14538                         return this;
14539                 }
14540
14541                 this.active = true;
14542
14543                 return this.parent(noFx);
14544         },
14545
14546         showMask: function(noFx){
14547                 var pos = function(){
14548                         this.content.position(Object.merge({
14549                                 relativeTo: this.element
14550                         }, this.options.containerPosition));
14551                 }.bind(this);
14552
14553                 if (noFx){
14554                         this.parent();
14555                         pos();
14556                 } else {
14557                         if (!this.options.style.opacity) this.options.style.opacity = this.element.getStyle('opacity').toFloat();
14558                         this.element.setStyles({
14559                                 display: 'block',
14560                                 opacity: 0
14561                         }).tween('opacity', this.options.style.opacity);
14562                         pos();
14563                         this.hidden = false;
14564                         this.fireEvent('show');
14565                         this.callChain();
14566                 }
14567         },
14568
14569         hide: function(noFx){
14570                 if (this.active) return this.chain(this.hide.bind(this));
14571                 if (this.hidden){
14572                         this.callChain.delay(20, this);
14573                         return this;
14574                 }
14575                 this.active = true;
14576                 return this.parent(noFx);
14577         },
14578
14579         hideMask: function(noFx){
14580                 if (noFx) return this.parent();
14581                 this.element.tween('opacity', 0).get('tween').chain(function(){
14582                         this.element.setStyle('display', 'none');
14583                         this.hidden = true;
14584                         this.fireEvent('hide');
14585                         this.callChain();
14586                 }.bind(this));
14587         },
14588
14589         destroy: function(){
14590                 this.content.destroy();
14591                 this.parent();
14592                 this.target.eliminate('spinner');
14593         }
14594
14595 });
14596
14597 Request = Class.refactor(Request, {
14598
14599         options: {
14600                 useSpinner: false,
14601                 spinnerOptions: {},
14602                 spinnerTarget: false
14603         },
14604
14605         initialize: function(options){
14606                 this._send = this.send;
14607                 this.send = function(options){
14608                         var spinner = this.getSpinner();
14609                         if (spinner) spinner.chain(this._send.pass(options, this)).show();
14610                         else this._send(options);
14611                         return this;
14612                 };
14613                 this.previous(options);
14614         },
14615
14616         getSpinner: function(){
14617                 if (!this.spinner){
14618                         var update = document.id(this.options.spinnerTarget) || document.id(this.options.update);
14619                         if (this.options.useSpinner && update){
14620                                 update.set('spinner', this.options.spinnerOptions);
14621                                 var spinner = this.spinner = update.get('spinner');
14622                                 ['complete', 'exception', 'cancel'].each(function(event){
14623                                         this.addEvent(event, spinner.hide.bind(spinner));
14624                                 }, this);
14625                         }
14626                 }
14627                 return this.spinner;
14628         }
14629
14630 });
14631
14632 Element.Properties.spinner = {
14633
14634         set: function(options){
14635                 var spinner = this.retrieve('spinner');
14636                 if (spinner) spinner.destroy();
14637                 return this.eliminate('spinner').store('spinner:options', options);
14638         },
14639
14640         get: function(){
14641                 var spinner = this.retrieve('spinner');
14642                 if (!spinner){
14643                         spinner = new Spinner(this, this.retrieve('spinner:options'));
14644                         this.store('spinner', spinner);
14645                 }
14646                 return spinner;
14647         }
14648
14649 };
14650
14651 Element.implement({
14652
14653         spin: function(options){
14654                 if (options) this.set('spinner', options);
14655                 this.get('spinner').show();
14656                 return this;
14657         },
14658
14659         unspin: function(){
14660                 this.get('spinner').hide();
14661                 return this;
14662         }
14663
14664 });
14665
14666
14667 // Begin: Source/Fx/Fx.Slide.js
14668 /*
14669 ---
14670
14671 script: Fx.Slide.js
14672
14673 name: Fx.Slide
14674
14675 description: Effect to slide an element in and out of view.
14676
14677 license: MIT-style license
14678
14679 authors:
14680   - Valerio Proietti
14681
14682 requires:
14683   - Core/Fx
14684   - Core/Element.Style
14685   - /MooTools.More
14686
14687 provides: [Fx.Slide]
14688
14689 ...
14690 */
14691
14692 Fx.Slide = new Class({
14693
14694         Extends: Fx,
14695
14696         options: {
14697                 mode: 'vertical',
14698                 wrapper: false,
14699                 hideOverflow: true,
14700                 resetHeight: false
14701         },
14702
14703         initialize: function(element, options){
14704                 element = this.element = this.subject = document.id(element);
14705                 this.parent(options);
14706                 options = this.options;
14707
14708                 var wrapper = element.retrieve('wrapper'),
14709                         styles = element.getStyles('margin', 'position', 'overflow');
14710
14711                 if (options.hideOverflow) styles = Object.append(styles, {overflow: 'hidden'});
14712                 if (options.wrapper) wrapper = document.id(options.wrapper).setStyles(styles);
14713
14714                 if (!wrapper) wrapper = new Element('div', {
14715                         styles: styles
14716                 }).wraps(element);
14717
14718                 element.store('wrapper', wrapper).setStyle('margin', 0);
14719                 if (element.getStyle('overflow') == 'visible') element.setStyle('overflow', 'hidden');
14720
14721                 this.now = [];
14722                 this.open = true;
14723                 this.wrapper = wrapper;
14724
14725                 this.addEvent('complete', function(){
14726                         this.open = (wrapper['offset' + this.layout.capitalize()] != 0);
14727                         if (this.open && this.options.resetHeight) wrapper.setStyle('height', '');
14728                 }, true);
14729         },
14730
14731         vertical: function(){
14732                 this.margin = 'margin-top';
14733                 this.layout = 'height';
14734                 this.offset = this.element.offsetHeight;
14735         },
14736
14737         horizontal: function(){
14738                 this.margin = 'margin-left';
14739                 this.layout = 'width';
14740                 this.offset = this.element.offsetWidth;
14741         },
14742
14743         set: function(now){
14744                 this.element.setStyle(this.margin, now[0]);
14745                 this.wrapper.setStyle(this.layout, now[1]);
14746                 return this;
14747         },
14748
14749         compute: function(from, to, delta){
14750                 return [0, 1].map(function(i){
14751                         return Fx.compute(from[i], to[i], delta);
14752                 });
14753         },
14754
14755         start: function(how, mode){
14756                 if (!this.check(how, mode)) return this;
14757                 this[mode || this.options.mode]();
14758
14759                 var margin = this.element.getStyle(this.margin).toInt(),
14760                         layout = this.wrapper.getStyle(this.layout).toInt(),
14761                         caseIn = [[margin, layout], [0, this.offset]],
14762                         caseOut = [[margin, layout], [-this.offset, 0]],
14763                         start;
14764
14765                 switch (how){
14766                         case 'in': start = caseIn; break;
14767                         case 'out': start = caseOut; break;
14768                         case 'toggle': start = (layout == 0) ? caseIn : caseOut;
14769                 }
14770                 return this.parent(start[0], start[1]);
14771         },
14772
14773         slideIn: function(mode){
14774                 return this.start('in', mode);
14775         },
14776
14777         slideOut: function(mode){
14778                 return this.start('out', mode);
14779         },
14780
14781         hide: function(mode){
14782                 this[mode || this.options.mode]();
14783                 this.open = false;
14784                 return this.set([-this.offset, 0]);
14785         },
14786
14787         show: function(mode){
14788                 this[mode || this.options.mode]();
14789                 this.open = true;
14790                 return this.set([0, this.offset]);
14791         },
14792
14793         toggle: function(mode){
14794                 return this.start('toggle', mode);
14795         }
14796
14797 });
14798
14799 Element.Properties.slide = {
14800
14801         set: function(options){
14802                 this.get('slide').cancel().setOptions(options);
14803                 return this;
14804         },
14805
14806         get: function(){
14807                 var slide = this.retrieve('slide');
14808                 if (!slide){
14809                         slide = new Fx.Slide(this, {link: 'cancel'});
14810                         this.store('slide', slide);
14811                 }
14812                 return slide;
14813         }
14814
14815 };
14816
14817 Element.implement({
14818
14819         slide: function(how, mode){
14820                 how = how || 'toggle';
14821                 var slide = this.get('slide'), toggle;
14822                 switch (how){
14823                         case 'hide': slide.hide(mode); break;
14824                         case 'show': slide.show(mode); break;
14825                         case 'toggle':
14826                                 var flag = this.retrieve('slide:flag', slide.open);
14827                                 slide[flag ? 'slideOut' : 'slideIn'](mode);
14828                                 this.store('slide:flag', !flag);
14829                                 toggle = true;
14830                         break;
14831                         default: slide.start(how, mode);
14832                 }
14833                 if (!toggle) this.eliminate('slide:flag');
14834                 return this;
14835         }
14836
14837 });
14838
14839
14840 // Begin: Source/UI/StickyWin.UI.Pointy.js
14841 /*
14842 ---
14843 name: StickyWin.UI.Pointy
14844
14845 description: Creates an html holder for in-page popups using a default style - this one including a pointer in the specified direction.
14846
14847 license: MIT-Style License
14848
14849 requires: [More/Element.Shortcuts, More/Element.Position, StickyWin.UI]
14850
14851 provides: [StickyWin.UI.Pointy, StickyWin.UI.pointy]
14852 ...
14853 */
14854 StickyWin.UI.Pointy = new Class({
14855         Extends: StickyWin.UI,
14856         options: {
14857                 theme: 'dark',
14858                 themes: {
14859                         dark: {
14860                                 bgColor: '#333',
14861                                 fgColor: '#ddd',
14862                                 imgset: 'dark'
14863                         },
14864                         light: {
14865                                 bgColor: '#ccc',
14866                                 fgColor: '#333',
14867                                 imgset: 'light'
14868                         }
14869                 },
14870                 css: "div.DefaultPointyTip {vertical-align: auto; position: relative;}"+
14871                 "div.DefaultPointyTip * {text-align:left !important}"+
14872                 "div.DefaultPointyTip .pointyWrapper div.body{background: {%bgColor%}; color: {%fgColor%}; left: 0px; right: 0px !important;padding:  0px 10px !important;margin-left: 0px !important;font-family: verdana;font-size: 11px;line-height: 13px;position: relative;}"+
14873                 "div.DefaultPointyTip .pointyWrapper div.top {position: relative;height: 25px; overflow: visible;}"+
14874                 "div.DefaultPointyTip .pointyWrapper div.top_ul{background: url({%baseHref%}{%imgset%}_back.png) top left no-repeat;width: 8px;height: 25px; position: absolute; left: 0px;}"+
14875                 "div.DefaultPointyTip .pointyWrapper div.top_ur{background: url({%baseHref%}{%imgset%}_back.png) top right !important;margin: 0 0 0 8px !important;height: 25px;position: relative;left: 0px !important;padding: 0;}"+
14876                 "div.DefaultPointyTip .pointyWrapper h1.caption{color: {%fgColor%};left: 0px !important;top: 4px !important;clear: none !important;overflow: hidden;font-weight: 700;font-size: 12px !important;position: relative;float: left;height: 22px !important;margin: 0 !important;padding: 0 !important;}"+
14877                 "div.DefaultPointyTip .pointyWrapper div.middle, div.DefaultPointyTip .pointyWrapper div.closeBody{background:  {%bgColor%};margin: 0 0px 0 0 !important;position: relative;top: 0 !important;}"+
14878                 "div.DefaultPointyTip .pointyWrapper div.middle {min-height: 16px; background:  {%bgColor%};margin: 0 0px 0 0 !important;position: relative;top: 0 !important;}"+
14879                 "div.DefaultPointyTip .pointyWrapper div.bottom {clear: both; width: 100% !important; background: none; height: 6px} "+
14880                 "div.DefaultPointyTip .pointyWrapper div.bottom_ll{font-size:1; background: url({%baseHref%}{%imgset%}_back.png) bottom left no-repeat;width: 6px;height: 6px;position: absolute; left: 0px;}"+
14881                 "div.DefaultPointyTip .pointyWrapper div.bottom_lr{font-size:1; background: url({%baseHref%}{%imgset%}_back.png) bottom right;height: 6px;margin: 0 0 0 6px !important;position: relative;left: 0 !important;}"+
14882                 "div.DefaultPointyTip .pointyWrapper div.noCaption{ height: 6px; overflow: hidden}"+
14883                 "div.DefaultPointyTip .pointyWrapper div.closeButton{width:13px; height:13px; background:url({%baseHref%}{%imgset%}_x.png) no-repeat; position: absolute; right: 0px; margin:0px !important; cursor:pointer; z-index: 1; top: 4px;}"+
14884                 "div.DefaultPointyTip .pointyWrapper div.pointyDivot {background: url({%divot%}) no-repeat;}",
14885                 divot: '{%baseHref%}{%imgset%}_divot.png',
14886                 divotSize: 22,
14887                 direction: 12,
14888                 cssId: 'defaultPointyTipStyle',
14889                 cssClassName: 'DefaultPointyTip'
14890         },
14891         initialize: function() {
14892                 var args = this.getArgs(arguments);
14893                 this.setOptions(args.options);
14894                 Object.append(this.options, this.options.themes[this.options.theme]);
14895                 this.options.baseHref = this.options.baseHref || Clientcide.assetLocation + '/PointyTip/';
14896                 this.options.divot = this.options.divot.substitute(this.options, /\\?\{%([^}]+)%\}/g);
14897                 if (Browser.ie) this.options.divot = this.options.divot.replace(/png/g, 'gif');
14898                 this.options.css = this.options.css.substitute(this.options, /\\?\{%([^}]+)%\}/g);
14899                 if (args.options && args.options.theme) {
14900                         while (!this.id) {
14901                                 var id = Number.random(0, 999999999);
14902                                 if (!StickyWin.UI.Pointy[id]) {
14903                                         StickyWin.UI.Pointy[id] = this;
14904                                         this.id = id;
14905                                 }
14906                         }
14907                         this.options.css = this.options.css.replace(/div\.DefaultPointyTip/g, "div#pointy_"+this.id);
14908                         this.options.cssId = "pointyTipStyle_" + this.id;
14909                 }
14910                 if (typeOf(this.options.direction) == 'string') {
14911                         var map = {
14912                                 left: 9,
14913                                 right: 3,
14914                                 up: 12,
14915                                 down: 6
14916                         };
14917                         this.options.direction = map[this.options.direction];
14918                 }
14919
14920                 this.parent(args.caption, args.body, this.options);
14921                 if (this.id) document.id(this).set('id', "pointy_"+this.id);
14922         },
14923         build: function(){
14924                 this.parent();
14925                 var opt = this.options;
14926                 this.pointyWrapper = new Element('div', {
14927                         'class': 'pointyWrapper'
14928                 }).inject(document.id(this));
14929                 document.id(this).getChildren().each(function(el){
14930                         if (el != this.pointyWrapper) this.pointyWrapper.grab(el);
14931                 }, this);
14932
14933                 var w = opt.divotSize;
14934                 var h = w;
14935                 var left = (opt.width.toInt() - opt.divotSize)/2;
14936                 var orient = function(){
14937                         switch(opt.direction) {
14938                                 case 12: case 1: case 11:
14939                                         return {
14940                                                 height: h/2
14941                                         };
14942                                 case 5: case 6: case 7:
14943                                         return {
14944                                                 height: h/2,
14945                                                 backgroundPosition: '0 -'+h/2+'px'
14946                                         };
14947                                 case 8: case 9: case 10:
14948                                         return {
14949                                                 width: w/2
14950                                         };
14951                                 case 2: case 3: case 4:
14952                                         return {
14953                                                 width: w/2,
14954                                                 backgroundPosition: '100%'
14955                                         };
14956                         };
14957                 };
14958                 this.pointer = new Element('div', {
14959                         styles: Object.append({
14960                                 width: w,
14961                                 height: h,
14962                                 overflow: 'hidden'
14963                         }, orient()),
14964                         'class': 'pointyDivot pointy_'+opt.direction
14965                 }).inject(this.pointyWrapper);
14966         },
14967         expose: function(){
14968                 if (document.id(this).getStyle('display') != 'none' &&
14969                   document.body != document.id(this) &&
14970                   document.id(document.body).contains(document.id(this))) return function(){};
14971                 document.id(this).setStyles({
14972                         visibility: 'hidden',
14973                         position: 'absolute'
14974                 });
14975                 var dispose;
14976                 if (document.body != document.id(this) && !document.body.contains(document.id(this))) {
14977                         document.id(this).inject(document.body);
14978                         dispose = true;
14979                 }
14980                 return (function(){
14981                         if (dispose) document.id(this).dispose();
14982                         document.id(this).setStyles({
14983                                 visibility: 'visible',
14984                                 position: 'relative'
14985                         });
14986                 }).bind(this);
14987         },
14988         positionPointer: function(options){
14989                 if (!this.pointer) return;
14990                 var opt = options || this.options;
14991                 var pos;
14992                 var d = opt.direction;
14993                 switch (d){
14994                         case 12: case 1: case 11:
14995                                 pos = {
14996                                         edge: {x: 'center', y: 'bottom'},
14997                                         position: {
14998                                                 x: d==12?'center':d==1?'right':'left',
14999                                                 y: 'top'
15000                                         },
15001                                         offset: {
15002                                                 x: (d==12?0:d==1?-1:1)*opt.divotSize,
15003                                                 y: 1
15004                                         }
15005                                 };
15006                                 break;
15007                         case 2: case 3: case 4:
15008                                 pos = {
15009                                         edge: {x: 'left', y: 'center'},
15010                                         position: {
15011                                                 x: 'right',
15012                                                 y: d==3?'center':d==2?'top':'bottom'
15013                                         },
15014                                         offset: {
15015                                                 x: -1,
15016                                                 y: (d==3?0:d==4?-1:1)*opt.divotSize
15017                                         }
15018                                 };
15019                                 break;
15020                         case 5: case 6: case 7:
15021                                 pos = {
15022                                         edge: {x: 'center', y: 'top'},
15023                                         position: {
15024                                                 x: d==6?'center':d==5?'right':'left',
15025                                                 y: 'bottom'
15026                                         },
15027                                         offset: {
15028                                                 x: (d==6?0:d==5?-1:1)*opt.divotSize,
15029                                                 y: -1
15030                                         }
15031                                 };
15032                                 break;
15033                         case 8: case 9: case 10:
15034                                 pos = {
15035                                         edge: {x: 'right', y: 'center'},
15036                                         position: {
15037                                                 x: 'left',
15038                                                 y: d==9?'center':d==10?'top':'bottom'
15039                                         },
15040                                         offset: {
15041                                                 x: 1,
15042                                                 y: (d==9?0:d==8?-1:1)*opt.divotSize
15043                                         }
15044                                 };
15045                                 break;
15046                 };
15047                 var putItBack = this.expose();
15048                 this.pointer.position(Object.append({
15049                         relativeTo: this.pointyWrapper,
15050                         allowNegative: true
15051                 }, pos, options));
15052                 putItBack();
15053         },
15054         setContent: function(a1, a2){
15055                 this.parent(a1, a2);
15056                 this.top[this.h1?'removeClass':'addClass']('noCaption');
15057                 if (Browser.ie) document.id(this).getElements('.bottom_ll, .bottom_lr').setStyle('font-size', 1); //IE6 bullshit
15058                 if (this.options.closeButton) this.body.setStyle('margin-right', 6);
15059                 this.positionPointer();
15060                 return this;
15061         },
15062         makeCaption: function(caption){
15063                 this.parent(caption);
15064                 if (this.options.width && this.h1) this.h1.setStyle('width', (this.options.width.toInt()-(this.options.closeButton?25:15)));
15065         }
15066 });
15067
15068 StickyWin.UI.pointy = function(caption, body, options){
15069         return document.id(new StickyWin.UI.Pointy(caption, body, options));
15070 };
15071 StickyWin.ui.pointy = StickyWin.UI.pointy;
15072
15073 // Begin: Source/UI/StickyWin.PointyTip.js
15074 /*
15075 ---
15076 name: StickyWin.PointyTip
15077
15078 description: Positions a pointy tip relative to the element you specify.
15079
15080 license: MIT-Style License
15081
15082 requires: StickyWin.UI.Pointy
15083
15084 provides: StickyWin.PointyTip
15085
15086 ...
15087 */
15088 StickyWin.PointyTip = new Class({
15089         Extends: StickyWin,
15090         options: {
15091                 point: "left",
15092                 pointyOptions: {}
15093         },
15094         initialize: function(){
15095                 var args = this.getArgs(arguments);
15096                 this.setOptions(args.options);
15097                 var popts = this.options.pointyOptions;
15098                 var d = popts.direction;
15099                 if (!d) {
15100                         var map = {
15101                                 left: 9,
15102                                 right: 3,
15103                                 up: 12,
15104                                 down: 6
15105                         };
15106                         d = map[this.options.point];
15107                         if (!d) d = this.options.point;
15108                         popts.direction = d;
15109                 }
15110                 if (!popts.width) popts.width = this.options.width;
15111                 this.pointy = new StickyWin.UI.Pointy(args.caption, args.body, popts);
15112                 this.options.content = null;
15113                 this.setOptions(args.options, this.getPositionSettings());
15114                 this.parent(this.options);
15115                 this.win.empty().adopt(document.id(this.pointy));
15116                 this.attachHandlers(this.win);
15117                 if (this.options.showNow) this.position();
15118         },
15119         getArgs: function(){
15120                 return StickyWin.UI.getArgs.apply(this, arguments);
15121         },
15122         getPositionSettings: function(){
15123                 var s = this.pointy.options.divotSize;
15124                 var d = this.options.point;
15125                 var offset = this.options.offset || {};
15126                 switch(d) {
15127                         case "left": case 8: case 9: case 10:
15128                                 return {
15129                                         edge: {
15130                                                 x: 'left',
15131                                                 y: d==10?'top':d==8?'bottom':'center'
15132                                         },
15133                                         position: {x: 'right', y: 'center'},
15134                                         offset: {
15135                                                 x: s + (offset.x || 0),
15136                                                 y: offset.y || 0
15137                                         }
15138                                 };
15139                         case "right": case 2:  case 3: case 4:
15140                                 return {
15141                                         edge: {
15142                                                 x: 'right',
15143                                                 y: (d==2?'top':d==4?'bottom':'center') + (offset.y || 0)
15144                                         },
15145                                         position: {x: 'left', y: 'center'},
15146                                         offset: {
15147                                                 x: -s + (offset.x || 0),
15148                                                 y: offset.y || 0
15149                                         }
15150                                 };
15151                         case "up": case 11: case 12: case 1:
15152                                 return {
15153                                         edge: {
15154                                                 x: d==11?'left':d==1?'right':'center',
15155                                                 y: 'top'
15156                                         },
15157                                         position: {     x: 'center', y: 'bottom' },
15158                                         offset: {
15159                                                 y: s + (offset.y || 0),
15160                                                 x: (d==11?-s:d==1?s:0) + (offset.x || 0)
15161                                         }
15162                                 };
15163                         case "down": case 5: case 6: case 7:
15164                                 return {
15165                                         edge: {
15166                                                 x: (d==7?'left':d==5?'right':'center') + (offset.x || 0),
15167                                                 y: 'bottom'
15168                                         },
15169                                         position: {x: 'center', y: 'top'},
15170                                         offset: {
15171                                                 y: -s + (offset.y || 0),
15172                                                 x: (d==7?-s:d==5?s:0) + (offset.x || 0)
15173                                         }
15174                                 };
15175                 };
15176         },
15177         setContent: function() {
15178                 var args = this.getArgs(arguments);
15179                 this.pointy.setContent(args.caption, args.body);
15180                 [this.pointy.h1, this.pointy.body].each(this.attachHandlers, this);
15181                 if (this.visible) this.position();
15182                 return this;
15183         },
15184         showWin: function(){
15185                 this.parent();
15186                 this.pointy.positionPointer();
15187         },
15188         position: function(options){
15189                 this.parent(options);
15190                 this.pointy.positionPointer();
15191         },
15192         attachHandlers: function(content) {
15193                 if (!content) return;
15194                 content.getElements('.'+this.options.closeClassName).addEvent('click', function(){ this.hide(); }.bind(this));
15195                 content.getElements('.'+this.options.pinClassName).addEvent('click', function(){ this.togglepin(); }.bind(this));
15196         }
15197 });
15198
15199 // Begin: Source/UI/StickyWin.Ajax.js
15200 /*
15201 ---
15202
15203 name: StickyWin.Ajax
15204
15205 description: Adds ajax functionality to all the StickyWin classes.
15206
15207 license: MIT-Style License
15208
15209 requires: [Core/Request, StickyWin, StickyWin.UI, StickyWin.PointyTip]
15210
15211 provides: [StickyWin.Ajax, StickyWin.Modal.Ajax, StickyWin.PointyTip.Ajax]
15212
15213 ...
15214 */
15215 (function(){
15216         var SWA = function(extend){
15217                 return {
15218                         Extends: extend,
15219                         options: {
15220                                 //onUpdate: function(){},
15221                                 url: '',
15222                                 showNow: false,
15223                                 cacheRequest: false,
15224                                 requestOptions: {
15225                                         method: 'get',
15226                                         evalScripts: true
15227                                 },
15228                                 wrapWithUi: false,
15229                                 caption: '',
15230                                 uiOptions:{},
15231                                 cacheRequest: false,
15232                                 handleResponse: function(response){
15233                                         if(this.options.cacheRequest) {
15234                                                 this.element.store(this.Request.options.url, response);
15235                                         }
15236                                         var responseScript = "";
15237                                         this.Request.response.text.stripScripts(function(script){       responseScript += script; });
15238                                         if (this.options.wrapWithUi) response = StickyWin.ui(this.options.caption, response, this.options.uiOptions);
15239                                         this.setContent(response);
15240                                         this.show();
15241                                         if (this.evalScripts) Browser.exec(responseScript);
15242                                         this.fireEvent('update');
15243                                 }
15244                         },
15245                         initialize: function(options){
15246                                 var showNow;
15247                                 if (options && options.showNow) {
15248                                         showNow = true;
15249                                         options.showNow = false;
15250                                 }
15251                                 this.parent(options);
15252                                 this.evalScripts = this.options.requestOptions.evalScripts;
15253                                 this.options.requestOptions.evalScripts = false;
15254                                 this.createRequest();
15255                                 if (showNow) this.update();
15256                         },
15257                         createRequest: function(){
15258                                 this.Request = new Request(this.options.requestOptions).addEvent('onSuccess',
15259                                         this.options.handleResponse.bind(this));
15260                         },
15261                         update: function(url, options){
15262                                 this.Request.options.url = url || options.url;
15263                                 var cachedResponse;
15264                                 if(this.options.cacheRequest) {
15265                                         cachedResponse = this.element.retrieve(url);
15266                                 }
15267                                 if(!cachedResponse) {
15268                                         this.Request.setOptions(options).send({url: url||this.options.url});
15269                                         return this;
15270                                 } else {
15271                                         this.Request.fireEvent('onSuccess', cachedResponse);
15272                                         return this;
15273                                 }
15274                         }
15275                 };
15276         };
15277         try { StickyWin.Ajax = new Class(SWA(StickyWin)); } catch(e){}
15278         try { StickyWin.Modal.Ajax = new Class(SWA(StickyWin.Modal)); } catch(e){}
15279         try { StickyWin.PointyTip.Ajax = new Class(SWA(StickyWin.PointyTip)); } catch(e){}
15280 })();
15281
15282 // Begin: Source/Layout/MultipleOpenAccordion.js
15283 /*
15284 ---
15285 name: MultipleOpenAccordion
15286
15287 description: Creates a Mootools Fx.Accordion that allows the user to open more than one element.
15288
15289 license: MIT-Style License
15290
15291 requires: [Core/Element.Event, More/Fx.Reveal]
15292
15293 provides: MultipleOpenAccordion
15294
15295 ...
15296 */
15297 var MultipleOpenAccordion = new Class({
15298         Implements: [Options, Events, Chain],
15299         options: {
15300                 togglers: [],
15301                 elements: [],
15302                 openAll: false,
15303                 firstElementsOpen: [0],
15304                 fixedHeight: null,
15305                 fixedWidth: null,
15306                 height: true,
15307                 opacity: true,
15308                 width: false
15309                 //onActive: function(){},
15310                 //onBackground: function(){}
15311         },
15312         togglers: [],
15313         elements: [],
15314         initialize: function(options){
15315                 var args = Array.link(arguments, {options: Type.isObject, elements: Type.isElements});
15316                 this.setOptions(args.options);
15317                 elements = $$(this.options.elements);
15318                 $$(this.options.togglers).each(function(toggler, idx){
15319                         this.addSection(toggler, elements[idx], idx);
15320                 }, this);
15321                 if (this.togglers.length) {
15322                         if (this.options.openAll) this.showAll();
15323                         else this.toggleSections(this.options.firstElementsOpen, false, true);
15324                 }
15325                 this.openSections = this.showSections.bind(this);
15326                 this.closeSections = this.hideSections.bind(this);
15327         },
15328         addSection: function(toggler, element){
15329                 toggler = document.id(toggler);
15330                 element = document.id(element);
15331                 var test = this.togglers.contains(toggler);
15332                 var len = this.togglers.length;
15333                 this.togglers.include(toggler);
15334                 this.elements.include(element);
15335                 var idx = this.togglers.indexOf(toggler);
15336                 var displayer = this.toggleSection.bind(this, idx);
15337                 toggler.addEvent('click', displayer).store('multipleOpenAccordion:display', displayer);
15338                 var mode;
15339                 if (this.options.height && this.options.width) mode = "both";
15340                 else mode = (this.options.height)?"vertical":"horizontal";
15341                 element.store('moa:reveal', new Fx.Reveal(element, {
15342                         transitionOpacity: this.options.opacity,
15343                         mode: mode,
15344                         heightOverride: this.options.fixedHeight,
15345                         widthOverride: this.options.fixedWidth
15346                 }));
15347                 return this;
15348         },
15349         removeSection: function(toggler) {
15350                 var idx = this.togglers.indexOf(toggler);
15351                 var element = this.elements[idx];
15352                 element.dissolve();
15353                 this.togglers.erase(toggler);
15354                 this.elements.erase(element);
15355                 this.detach(toggler);
15356                 return this;
15357         },
15358         detach: function(toggler){
15359                 var remove = function(toggler) {
15360                         toggler.removeEvent(this.options.trigger, toggler.retrieve('multipleOpenAccordion:display'));
15361                 }.bind(this);
15362                 if (!toggler) this.togglers.each(remove);
15363                 else remove(toggler);
15364                 return this;
15365         },
15366         onComplete: function(idx, callChain){
15367                 this.fireEvent(this.elements[idx].isDisplayed()?'onActive':'onBackground', [this.togglers[idx], this.elements[idx]]);
15368                 this.callChain();
15369                 return this;
15370         },
15371         showSection: function(idx, useFx){
15372                 this.toggleSection(idx, useFx, true);
15373         },
15374         hideSection: function(idx, useFx){
15375                 this.toggleSection(idx, useFx, false);
15376         },
15377         toggleSection: function(idx, useFx, show, callChain){
15378                 var method = show?'reveal':show != null?'dissolve':'toggle';
15379                 callChain = [callChain, true].pick();
15380                 var el = this.elements[idx];
15381                 if (useFx != null ? useFx : true) {
15382                         el.retrieve('moa:reveal')[method]().chain(
15383                                 this.onComplete.bind(this, idx, callChain)
15384                         );
15385                 } else {
15386                                 if (method == "toggle") el.toggle();
15387                                 else el[method == "reveal"?'show':'hide']();
15388                                 this.onComplete(idx, callChain);
15389                 }
15390                 return this;
15391         },
15392         toggleAll: function(useFx, show){
15393                 var method = show?'reveal':(show!=null)?'disolve':'toggle';
15394                 var last = this.elements.getLast();
15395                 this.elements.each(function(el, idx){
15396                         this.toggleSection(idx, useFx, show, el == last);
15397                 }, this);
15398                 return this;
15399         },
15400         toggleSections: function(sections, useFx, show) {
15401                 last = sections.getLast();
15402                 this.elements.each(function(el,idx){
15403                         this.toggleSection(idx, useFx, sections.contains(idx)?show:!show, idx == last);
15404                 }, this);
15405                 return this;
15406         },
15407         showSections: function(sections, useFx){
15408                 sections.each(function(i){
15409                         this.showSection(i, useFx);
15410                 }, this);
15411         },
15412         hideSections: function(sections, useFx){
15413                 sections.each(function(i){
15414                         this.hideSection(i, useFx);
15415                 }, this);
15416         },
15417         showAll: function(useFx){
15418                 return this.toggleAll(useFx, true);
15419         },
15420         hideAll: function(useFx){
15421                 return this.toggleAll(useFx, false);
15422         }
15423 });
15424
15425