Upgrade to ExtJS 3.3.1 - Released 11/30/2010
[extjs.git] / examples / docs / source / Focus.html
1 <html>
2 <head>
3   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    
4   <title>The source code</title>
5     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
6     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
7 </head>
8 <body  onload="prettyPrint();">
9     <pre class="prettyprint lang-js">/*!
10  * Ext JS Library 3.3.1
11  * Copyright(c) 2006-2010 Sencha Inc.
12  * licensing@sencha.com
13  * http://www.sencha.com/license
14  */
15 (function(){
16 Ext.ns('Ext.a11y');
17
18 Ext.a11y.Frame = Ext.extend(Object, {
19     initialized: false,
20     
21     constructor: function(size, color){
22         this.setSize(size || 1);
23         this.setColor(color || '15428B');
24     },
25     
26     init: function(){
27         if (!this.initialized) {
28             this.sides = [];
29             
30             var s, i;
31             
32             this.ct = Ext.DomHelper.append(document.body, {
33                 cls: 'x-a11y-focusframe'
34             }, true);
35             
36             for (i = 0; i < 4; i++) {
37                 s = Ext.DomHelper.append(this.ct, {
38                     cls: 'x-a11y-focusframe-side',
39                     style: 'background-color: #' + this.color
40                 }, true);
41                 s.visibilityMode = Ext.Element.DISPLAY;
42                 this.sides.push(s);
43             }
44             
45             this.frameTask = new Ext.util.DelayedTask(function(el){
46                 var newEl = Ext.get(el);
47                 if (newEl != this.curEl) {
48                     var w = newEl.getWidth();
49                     var h = newEl.getHeight();
50                     this.sides[0].show().setSize(w, this.size).anchorTo(el, 'tl', [0, -1]);
51                     this.sides[2].show().setSize(w, this.size).anchorTo(el, 'bl', [0, -1]);
52                     this.sides[1].show().setSize(this.size, h).anchorTo(el, 'tr', [-1, 0]);
53                     this.sides[3].show().setSize(this.size, h).anchorTo(el, 'tl', [-1, 0]);
54                     this.curEl = newEl;
55                 }
56             }, this);
57             
58             this.unframeTask = new Ext.util.DelayedTask(function(){
59                 if (this.initialized) {
60                     this.sides[0].hide();
61                     this.sides[1].hide();
62                     this.sides[2].hide();
63                     this.sides[3].hide();
64                     this.curEl = null;
65                 }
66             }, this);
67             this.initialized = true;
68         }
69     },
70     
71     frame: function(el){
72         this.init();
73         this.unframeTask.cancel();
74         this.frameTask.delay(2, false, false, [el]);
75     },
76     
77     unframe: function(){
78         this.init();
79         this.unframeTask.delay(2);
80     },
81     
82     setSize: function(size){
83         this.size = size;
84     },
85     
86     setColor: function(color){
87         this.color = color;
88     }
89 });
90
91 Ext.a11y.FocusFrame = new Ext.a11y.Frame(2, '15428B');
92 Ext.a11y.RelayFrame = new Ext.a11y.Frame(1, '6B8CBF');
93
94 Ext.a11y.Focusable = Ext.extend(Ext.util.Observable, {
95     constructor: function(el, relayTo, noFrame, frameEl){
96         Ext.a11y.Focusable.superclass.constructor.call(this);
97         
98         this.addEvents('focus', 'blur', 'left', 'right', 'up', 'down', 'esc', 'enter', 'space');
99         
100         if (el instanceof Ext.Component) {
101             this.el = el.el;
102             this.setComponent(el);
103         }
104         else {
105             this.el = Ext.get(el);
106             this.setComponent(null);
107         }
108         
109         this.setRelayTo(relayTo)
110         this.setNoFrame(noFrame);
111         this.setFrameEl(frameEl);
112         
113         this.init();
114         
115         Ext.a11y.FocusMgr.register(this);
116     },
117     
118     init: function(){
119         this.el.dom.tabIndex = '1';
120         this.el.addClass('x-a11y-focusable');
121         this.el.on({
122             focus: this.onFocus,
123             blur: this.onBlur,
124             keydown: this.onKeyDown,
125             scope: this
126         });
127     },
128     
129     setRelayTo: function(relayTo){
130         this.relayTo = relayTo ? Ext.a11y.FocusMgr.get(relayTo) : null;
131     },
132     
133     setNoFrame: function(noFrame){
134         this.noFrame = (noFrame === true) ? true : false;
135     },
136     
137     setFrameEl: function(frameEl){
138         this.frameEl = frameEl && Ext.get(frameEl) || this.el;
139     },
140     
141     setComponent: function(cmp){
142         this.component = cmp || null;
143     },
144     
145     onKeyDown: function(e, t){
146         var k = e.getKey(), SK = Ext.a11y.Focusable.SpecialKeys, ret, tf;
147         
148         tf = (t !== this.el.dom) ? Ext.a11y.FocusMgr.get(t, true) : this;
149         if (!tf) {
150             // this can happen when you are on a focused item within a panel body
151             // that is not a Ext.a11y.Focusable
152             tf = Ext.a11y.FocusMgr.get(Ext.fly(t).parent('.x-a11y-focusable'));
153         }
154         
155         if (SK[k] !== undefined) {
156             ret = this.fireEvent(SK[k], e, t, tf, this);
157         }
158         if (ret === false || this.fireEvent('keydown', e, t, tf, this) === false) {
159             e.stopEvent();
160         }
161     },
162     
163     focus: function(){
164         this.el.dom.focus();
165     },
166     
167     blur: function(){
168         this.el.dom.blur();
169     },
170     
171     onFocus: function(e, t){
172         this.el.addClass('x-a11y-focused');
173         if (this.relayTo) {
174             this.relayTo.el.addClass('x-a11y-focused-relay');
175             if (!this.relayTo.noFrame) {
176                 Ext.a11y.FocusFrame.frame(this.relayTo.frameEl);
177             }
178             if (!this.noFrame) {
179                 Ext.a11y.RelayFrame.frame(this.frameEl);
180             }
181         }
182         else {
183             if (!this.noFrame) {
184                 Ext.a11y.FocusFrame.frame(this.frameEl);
185             }
186         }
187         
188         this.fireEvent('focus', e, t, this);
189     },
190     
191     onBlur: function(e, t){
192         if (this.relayTo) {
193             this.relayTo.el.removeClass('x-a11y-focused-relay');
194             Ext.a11y.RelayFrame.unframe();
195         }
196         this.el.removeClass('x-a11y-focused');
197         Ext.a11y.FocusFrame.unframe();
198         this.fireEvent('blur', e, t, this);
199     },
200     
201     destroy: function(){
202         this.el.un('keydown', this.onKeyDown);
203         this.el.un('focus', this.onFocus);
204         this.el.un('blur', this.onBlur);
205         this.el.removeClass('x-a11y-focusable');
206         this.el.removeClass('x-a11y-focused');
207         if (this.relayTo) {
208             this.relayTo.el.removeClass('x-a11y-focused-relay');
209         }
210     }
211 });
212
213 Ext.a11y.FocusItem = Ext.extend(Object, {
214     constructor: function(el, enableTabbing){
215         Ext.a11y.FocusItem.superclass.constructor.call(this);
216         
217         this.el = Ext.get(el);
218         this.fi = new Ext.a11y.Focusable(el);
219         this.fi.setComponent(this);
220         
221         this.fi.on('tab', this.onTab, this);
222         
223         this.enableTabbing = enableTabbing === true ? true : false;
224     },
225     
226     getEnterItem: function(){
227         if (this.enableTabbing) {
228             var items = this.getFocusItems();
229             if (items && items.length) {
230                 return items[0];
231             }
232         }
233     },
234     
235     getFocusItems: function(){
236         if (this.enableTabbing) {
237             return this.el.query('a, button, input, select');
238         }
239         return null;
240     },
241     
242     onTab: function(e, t){
243         var items = this.getFocusItems(), i;
244         
245         if (items && items.length && (i = items.indexOf(t)) !== -1) {
246             if (e.shiftKey && i > 0) {
247                 e.stopEvent();
248                 items[i - 1].focus();
249                 Ext.a11y.FocusFrame.frame.defer(20, Ext.a11y.FocusFrame, [this.el]);
250                 return;
251             }
252             else 
253                 if (!e.shiftKey && i < items.length - 1) {
254                     e.stopEvent();
255                     items[i + 1].focus();
256                     Ext.a11y.FocusFrame.frame.defer(20, Ext.a11y.FocusFrame, [this.el]);
257                     return;
258                 }
259         }
260     },
261     
262     focus: function(){
263         if (this.enableTabbing) {
264             var items = this.getFocusItems();
265             if (items && items.length) {
266                 items[0].focus();
267                 Ext.a11y.FocusFrame.frame.defer(20, Ext.a11y.FocusFrame, [this.el]);
268                 return;
269             }
270         }
271         this.fi.focus();
272     },
273     
274     blur: function(){
275         this.fi.blur();
276     }
277 });
278
279 Ext.a11y.FocusMgr = function(){
280     var all = new Ext.util.MixedCollection();
281     
282     return {
283         register: function(f){
284             all.add(f.el && Ext.id(f.el), f);
285         },
286         
287         unregister: function(f){
288             all.remove(f);
289         },
290         
291         get: function(el, noCreate){
292             return all.get(Ext.id(el)) || (noCreate ? false : new Ext.a11y.Focusable(el));
293         },
294         
295         all: all
296     }
297 }();
298
299 Ext.a11y.Focusable.SpecialKeys = {};
300 Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.LEFT] = 'left';
301 Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.RIGHT] = 'right';
302 Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.DOWN] = 'down';
303 Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.UP] = 'up';
304 Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.ESC] = 'esc';
305 Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.ENTER] = 'enter';
306 Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.SPACE] = 'space';
307 Ext.a11y.Focusable.SpecialKeys[Ext.EventObjectImpl.prototype.TAB] = 'tab';
308
309 // we use the new observeClass method to fire our new initFocus method on components
310 Ext.util.Observable.observeClass(Ext.Component);
311 Ext.Component.on('render', function(cmp){
312     cmp.initFocus();
313     cmp.initARIA();
314 });
315 Ext.override(Ext.Component, {
316     initFocus: Ext.emptyFn,
317     initARIA: Ext.emptyFn
318 });
319
320 Ext.override(Ext.Container, {
321     isFocusable: true,
322     noFocus: false,
323     
324     // private
325     initFocus: function(){
326         if (!this.fi && !this.noFocus) {
327             this.fi = new Ext.a11y.Focusable(this);
328         }
329         this.mon(this.fi, {
330             focus: this.onFocus,
331             blur: this.onBlur,
332             tab: this.onTab,
333             enter: this.onEnter,
334             esc: this.onEsc,
335             scope: this
336         });
337         
338         if (this.hidden) {
339             this.isFocusable = false;
340         }
341         
342         this.on('show', function(){
343             this.isFocusable = true;
344         }, this);
345         this.on('hide', function(){
346             this.isFocusable = false;
347         }, this);
348     },
349     
350     focus: function(){
351         this.fi.focus();
352     },
353     
354     blur: function(){
355         this.fi.blur();
356     },
357     
358     enter: function(){
359         var eitem = this.getEnterItem();
360         if (eitem) {
361             eitem.focus();
362         }
363     },
364     
365     onFocus: Ext.emptyFn,
366     onBlur: Ext.emptyFn,
367     
368     onTab: function(e, t, tf){
369         var rf = tf.relayTo || tf;
370         if (rf.component && rf.component !== this) {
371             e.stopEvent();
372             var item = e.shiftKey ? this.getPreviousFocus(rf.component) : this.getNextFocus(rf.component);
373             item.focus();
374         }
375     },
376     
377     onEnter: function(e, t, tf){
378         // check to see if enter is pressed while "on" the panel
379         if (tf.component && tf.component === this) {
380             e.stopEvent();
381             this.enter();
382         }
383         e.stopPropagation();
384     },
385     
386     onEsc: function(e, t){
387         e.preventDefault();
388         
389         // check to see if esc is pressed while "inside" the panel
390         // or while "on" the panel
391         if (t === this.el.dom) {
392             // "on" the panel, check if this panel has an owner panel and focus that
393             // we dont stop the event in this case so that this same check will be
394             // done for this ownerCt
395             if (this.ownerCt) {
396                 this.ownerCt.focus();
397             }
398         }
399         else {
400             // we were inside the panel when esc was pressed,
401             // so go back "on" the panel
402             if (this.ownerCt && this.ownerCt.isFocusable) {
403                 var si = this.ownerCt.getFocusItems();
404                 
405                 if (si && si.getCount() > 1) {
406                     e.stopEvent();
407                 }
408             }
409             this.focus();
410         }
411     },
412     
413     getFocusItems: function(){
414         return this.items &&
415             this.items.filterBy(function(o){
416                 return o.isFocusable;
417             }) ||
418             null;
419     },
420     
421     getEnterItem: function(){
422         var ci = this.getFocusItems(), length = ci ? ci.getCount() : 0;
423         
424         if (length === 1) {
425             return ci.first().getEnterItem && ci.first().getEnterItem() || ci.first();
426         }
427         else if (length > 1) {
428             return ci.first();
429         }
430     },
431     
432     getNextFocus: function(current){
433         var items = this.getFocusItems(), next = current, i = items.indexOf(current), length = items.getCount();
434         
435         if (i === length - 1) {
436             next = items.first();
437         }
438         else {
439             next = items.get(i + 1);
440         }
441         return next;
442     },
443     
444     getPreviousFocus: function(current){
445         var items = this.getFocusItems(), prev = current, i = items.indexOf(current), length = items.getCount();
446         
447         if (i === 0) {
448             prev = items.last();
449         }
450         else {
451             prev = items.get(i - 1);
452         }
453         return prev;
454     },
455     
456     getFocusable : function() {
457         return this.fi;
458     }
459 });
460
461 Ext.override(Ext.Panel, {
462     <div id="cfg-Ext.ux.DataViewTransition-enableTabbing"></div>/**
463      * @cfg {Boolean} enableTabbing <tt>true</tt> to enable tabbing. Default is <tt>false</tt>.
464      */        
465     getFocusItems: function(){
466         // items gets all the items inside the body
467         var items = Ext.Panel.superclass.getFocusItems.call(this), bodyFocus = null;
468
469         if (!items) {
470             items = new Ext.util.MixedCollection();
471             this.bodyFocus = this.bodyFocus || new Ext.a11y.FocusItem(this.body, this.enableTabbing);
472             items.add('body', this.bodyFocus);
473         }
474         // but panels can also have tbar, bbar, fbar
475         if (this.tbar && this.topToolbar) {
476             items.insert(0, this.topToolbar);
477         }
478         if (this.bbar && this.bottomToolbar) {
479             items.add(this.bottomToolbar);
480         }
481         if (this.fbar) {
482             items.add(this.fbar);
483         }
484         
485         return items;
486     }
487 });
488
489 Ext.override(Ext.TabPanel, {
490     // private
491     initFocus: function(){
492         Ext.TabPanel.superclass.initFocus.call(this);
493         this.mon(this.fi, {
494             left: this.onLeft,
495             right: this.onRight,
496             scope: this
497         });
498     },
499     
500     onLeft: function(e){
501         if (!this.activeTab) {
502             return;
503         }
504         e.stopEvent();
505         var prev = this.items.itemAt(this.items.indexOf(this.activeTab) - 1);
506         if (prev) {
507             this.setActiveTab(prev);
508         }
509         return false;
510     },
511     
512     onRight: function(e){
513         if (!this.activeTab) {
514             return;
515         }
516         e.stopEvent();
517         var next = this.items.itemAt(this.items.indexOf(this.activeTab) + 1);
518         if (next) {
519             this.setActiveTab(next);
520         }
521         return false;
522     }
523 });
524
525 Ext.override(Ext.tree.TreeNodeUI, {
526     // private
527     focus: function(){
528         this.node.getOwnerTree().bodyFocus.focus();
529     }
530 });
531
532 Ext.override(Ext.tree.TreePanel, {
533     // private
534     afterRender : function(){
535         Ext.tree.TreePanel.superclass.afterRender.call(this);
536         this.root.render();
537         if(!this.rootVisible){
538             this.root.renderChildren();
539         }
540         this.bodyFocus = new Ext.a11y.FocusItem(this.body.down('.x-tree-root-ct'));
541         this.bodyFocus.fi.setFrameEl(this.body);
542     } 
543 });
544
545 Ext.override(Ext.grid.GridPanel, {
546     initFocus: function(){
547         Ext.grid.GridPanel.superclass.initFocus.call(this);
548         this.bodyFocus = new Ext.a11y.FocusItem(this.view.focusEl);
549         this.bodyFocus.fi.setFrameEl(this.body);
550     }
551 });
552
553 Ext.override(Ext.Button, {
554     isFocusable: true,
555     noFocus: false,
556     
557     initFocus: function(){
558         Ext.Button.superclass.initFocus.call(this);
559         this.fi = this.fi || new Ext.a11y.Focusable(this.btnEl, null, null, this.el);
560         this.fi.setComponent(this);
561         
562         this.mon(this.fi, {
563             focus: this.onFocus,
564             blur: this.onBlur,
565             scope: this
566         });
567         
568         if (this.menu) {
569             this.mon(this.fi, 'down', this.showMenu, this);
570             this.on('menuhide', this.focus, this);
571         }
572         
573         if (this.hidden) {
574             this.isFocusable = false;
575         }
576         
577         this.on('show', function(){
578             this.isFocusable = true;
579         }, this);
580         this.on('hide', function(){
581             this.isFocusable = false;
582         }, this);
583     },
584     
585     focus: function(){
586         this.fi.focus();
587     },
588     
589     blur: function(){
590         this.fi.blur();
591     },
592     
593     onFocus: function(){
594         if (!this.disabled) {
595             this.el.addClass("x-btn-focus");
596         }
597     },
598     
599     onBlur: function(){
600         this.el.removeClass("x-btn-focus");
601     }
602 });
603
604 Ext.override(Ext.Toolbar, {
605     initFocus: function(){
606         Ext.Toolbar.superclass.initFocus.call(this);
607         this.mon(this.fi, {
608             left: this.onLeft,
609             right: this.onRight,
610             scope: this
611         });
612         
613         this.on('focus', this.onButtonFocus, this, {
614             stopEvent: true
615         });
616     },
617     
618     add: function(){
619         var item = Ext.Toolbar.superclass.add.apply(this, arguments);
620         if(!item || !item.events) {
621             return item;
622         }
623         if (item.rendered && item.fi !== undefined) {
624             item.fi.setRelayTo(this.el);
625             this.relayEvents(item.fi, ['focus']);
626         }
627         else {
628             item.on('render', function(){
629                 if (item.fi !== undefined) {
630                     item.fi.setRelayTo(this.el);
631                     this.relayEvents(item.fi, ['focus']);
632                 }
633             }, this, {
634                 single: true
635             });
636         }
637         return item;
638     },
639     
640     onFocus: function(){
641         var items = this.getFocusItems();
642         if (items && items.getCount() > 0) {
643             if (this.lastFocus && items.indexOf(this.lastFocus) !== -1) {
644                 this.lastFocus.focus();
645             }
646             else {
647                 items.first().focus();
648             }
649         }
650     },
651     
652     onButtonFocus: function(e, t, tf){
653         this.lastFocus = tf.component || null;
654     },
655     
656     onLeft: function(e, t, tf){
657         e.stopEvent();
658         this.getPreviousFocus(tf.component).focus();
659     },
660     
661     onRight: function(e, t, tf){
662         e.stopEvent();
663         this.getNextFocus(tf.component).focus();
664     },
665     
666     getEnterItem: Ext.emptyFn,
667     onTab: Ext.emptyFn,
668     onEsc: Ext.emptyFn
669 });
670
671 Ext.override(Ext.menu.BaseItem, {
672     initFocus: function(){
673         this.fi = new Ext.a11y.Focusable(this, this.parentMenu && this.parentMenu.el || null, true);
674     }
675 });
676
677 Ext.override(Ext.menu.Menu, {
678     initFocus: function(){
679         this.fi = new Ext.a11y.Focusable(this);
680         this.focusEl = this.fi;
681     }
682 });
683
684 Ext.a11y.WindowMgr = new Ext.WindowGroup();
685
686 Ext.apply(Ext.WindowMgr, {
687     bringToFront: function(win){
688         Ext.a11y.WindowMgr.bringToFront.call(this, win);
689         if (win.modal) {
690             win.enter();
691         }
692         else {
693             win.focus();
694         }
695     }
696 });
697
698 Ext.override(Ext.Window, {
699     initFocus: function(){
700         Ext.Window.superclass.initFocus.call(this);
701         this.on('beforehide', function(){
702             Ext.a11y.RelayFrame.unframe();
703             Ext.a11y.FocusFrame.unframe();
704         });
705     }
706 });
707
708 Ext.override(Ext.form.Field, {
709     isFocusable: true,
710     noFocus: false,
711     
712     initFocus: function(){
713         this.fi = this.fi || new Ext.a11y.Focusable(this, null, true);
714         
715         Ext.form.Field.superclass.initFocus.call(this);
716         
717         if (this.hidden) {
718             this.isFocusable = false;
719         }
720         
721         this.on('show', function(){
722             this.isFocusable = true;
723         }, this);
724         this.on('hide', function(){
725             this.isFocusable = false;
726         }, this);
727     }
728 });
729
730 Ext.override(Ext.FormPanel, {
731     initFocus: function(){
732         Ext.FormPanel.superclass.initFocus.call(this);
733         this.on('focus', this.onFieldFocus, this, {
734             stopEvent: true
735         });
736     },
737     
738     // private
739     createForm: function(){
740         delete this.initialConfig.listeners;
741         var form = new Ext.form.BasicForm(null, this.initialConfig);
742         form.afterMethod('add', this.formItemAdd, this);
743         return form;
744     },
745     
746     formItemAdd: function(item){
747         item.on('render', function(field){
748             field.fi.setRelayTo(this.el);
749             this.relayEvents(field.fi, ['focus']);
750         }, this, {
751             single: true
752         });
753     },
754     
755     onFocus: function(){
756         var items = this.getFocusItems();
757         if (items && items.getCount() > 0) {
758             if (this.lastFocus && items.indexOf(this.lastFocus) !== -1) {
759                 this.lastFocus.focus();
760             }
761             else {
762                 items.first().focus();
763             }
764         }
765     },
766     
767     onFieldFocus: function(e, t, tf){
768         this.lastFocus = tf.component || null;
769     },
770     
771     onTab: function(e, t, tf){
772         if (tf.relayTo.component === this) {
773             var item = e.shiftKey ? this.getPreviousFocus(tf.component) : this.getNextFocus(tf.component);
774             
775             if (item) {
776                 ev.stopEvent();
777                 item.focus();
778                 return;
779             }
780         }
781         Ext.FormPanel.superclass.onTab.apply(this, arguments);
782     },
783     
784     getNextFocus: function(current){
785         var items = this.getFocusItems(), i = items.indexOf(current), length = items.getCount();
786         
787         return (i < length - 1) ? items.get(i + 1) : false;
788     },
789     
790     getPreviousFocus: function(current){
791         var items = this.getFocusItems(), i = items.indexOf(current), length = items.getCount();
792         
793         return (i > 0) ? items.get(i - 1) : false;
794     }
795 });
796
797 Ext.override(Ext.Viewport, {
798     initFocus: function(){
799         Ext.Viewport.superclass.initFocus.apply(this);
800         this.mon(Ext.get(document), 'focus', this.focus, this);
801         this.mon(Ext.get(document), 'blur', this.blur, this);
802         this.fi.setNoFrame(true);
803     },
804     
805     onTab: function(e, t, tf, f){
806         e.stopEvent();
807         
808         if (tf === f) {
809             items = this.getFocusItems();
810             if (items && items.getCount() > 0) {
811                 items.first().focus();
812             }
813         }
814         else {
815             var rf = tf.relayTo || tf;
816             var item = e.shiftKey ? this.getPreviousFocus(rf.component) : this.getNextFocus(rf.component);
817             item.focus();
818         }
819     }
820 });
821     
822 })();</pre>    
823 </body>
824 </html>